diff --git a/.idea/runConfigurations/stm32g474_jlink.xml b/.idea/runConfigurations/stm32g474_jlink.xml new file mode 100644 index 000000000..45a755da4 --- /dev/null +++ b/.idea/runConfigurations/stm32g474_jlink.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/README.rst b/README.rst index 425cfa0e3..2c9119fef 100644 --- a/README.rst +++ b/README.rst @@ -20,8 +20,8 @@ Please take a look at the online `documentation `__. ├── docs # Documentation ├── examples # Sample with Makefile build support ├── hw - │   ├── bsp # Supported boards source files - │   └── mcu # Low level mcu core & peripheral drivers + │ ├── bsp # Supported boards source files + │ └── mcu # Low level mcu core & peripheral drivers ├── lib # Sources from 3rd party such as freeRTOS, fatfs ... ├── src # All sources files for TinyUSB stack itself. ├── test # Unit tests for the stack @@ -89,6 +89,13 @@ Host Stack - Mass Storage Class (MSC) - Hub with multiple-level support +TypeC PD Stack +============== + +- Power Delivery 3.0 (PD3.0) with USB Type-C support (WIP) +- Super early stage, only for testing purpose +- Only support STM32 G4 + OS Abstraction layer ==================== diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 91c9fb098..c603d0c22 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -8,3 +8,4 @@ project(tinyusb_examples C CXX ASM) add_subdirectory(device) add_subdirectory(dual) add_subdirectory(host) +add_subdirectory(typec) diff --git a/examples/typec/CMakeLists.txt b/examples/typec/CMakeLists.txt new file mode 100644 index 000000000..c7641494e --- /dev/null +++ b/examples/typec/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.17) + +include(${CMAKE_CURRENT_SOURCE_DIR}/../../hw/bsp/family_support.cmake) + +project(tinyusb_host_examples C CXX ASM) +family_initialize_project(tinyusb_host_examples ${CMAKE_CURRENT_LIST_DIR}) + +# family_add_subdirectory will filter what to actually add based on selected FAMILY +family_add_subdirectory(power_delivery) diff --git a/examples/typec/power_delivery/CMakeLists.txt b/examples/typec/power_delivery/CMakeLists.txt new file mode 100644 index 000000000..4ab8d5a65 --- /dev/null +++ b/examples/typec/power_delivery/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.17) + +include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake) + +# gets PROJECT name for the example (e.g. -) +family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR}) + +project(${PROJECT} C CXX ASM) + +# Checks this example is valid for the family and initializes the project +family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}) + +# Espressif has its own cmake build system +if(FAMILY STREQUAL "espressif") + return() +endif() + +add_executable(${PROJECT}) + +# Example source +target_sources(${PROJECT} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c + ) + +# Example include +target_include_directories(${PROJECT} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/src + ) + +# Configure compilation flags and libraries for the example... see the corresponding function +# in hw/bsp/FAMILY/family.cmake for details. +family_configure_device_example(${PROJECT}) diff --git a/examples/typec/power_delivery/Makefile b/examples/typec/power_delivery/Makefile new file mode 100644 index 000000000..2a3d854fb --- /dev/null +++ b/examples/typec/power_delivery/Makefile @@ -0,0 +1,11 @@ +include ../../make.mk + +INC += \ + src \ + $(TOP)/hw \ + +# Example source +EXAMPLE_SOURCE += $(wildcard src/*.c) +SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE)) + +include ../../rules.mk diff --git a/examples/typec/power_delivery/only.txt b/examples/typec/power_delivery/only.txt new file mode 100644 index 000000000..657aeaac5 --- /dev/null +++ b/examples/typec/power_delivery/only.txt @@ -0,0 +1 @@ +mcu:STM32G4 diff --git a/examples/typec/power_delivery/src/main.c b/examples/typec/power_delivery/src/main.c new file mode 100644 index 000000000..342a2235f --- /dev/null +++ b/examples/typec/power_delivery/src/main.c @@ -0,0 +1,195 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include +#include + +#include "bsp/board.h" +#include "tusb.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF PROTOTYPES +//--------------------------------------------------------------------+ + +// Voltage and current for selecting PDO +// DANGEROUS: Please make sure your board can withstand the voltage and current +// defined here. Otherwise, you may damage your board, smoke can come out +#define VOLTAGE_MAX_MV 5000 // maximum voltage in mV +#define CURRENT_MAX_MA 500 // maximum current in mA +#define CURRENT_OPERATING_MA 100 // operating current in mA + +/* Blink pattern + * - 250 ms : button is not pressed + * - 1000 ms : button is pressed (and hold) + */ +enum { + BLINK_PRESSED = 250, + BLINK_UNPRESSED = 1000 +}; + +static uint32_t blink_interval_ms = BLINK_UNPRESSED; + +void led_blinking_task(void); + +#define HELLO_STR "Hello from TinyUSB\r\n" + +int main(void) +{ + board_init(); + board_led_write(true); + + tuc_init(0, TUSB_TYPEC_PORT_SNK); + + uint32_t start_ms = 0; + bool led_state = false; + + while (1) { + led_blinking_task(); + + // tinyusb typec task + tuc_task(); + } +} + +#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3 +void app_main(void) +{ + main(); +} +#endif + +//--------------------------------------------------------------------+ +// TypeC PD callbacks +//--------------------------------------------------------------------+ + +bool tuc_pd_data_received_cb(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end) { + switch (header->msg_type) { + case PD_DATA_SOURCE_CAP: { + printf("PD Source Capabilities\r\n"); + // Examine source capability and select a suitable PDO (starting from 1 with safe5v) + uint8_t selected_pos = 1; + + for(size_t i=0; in_data_obj; i++) { + TU_VERIFY(dobj < p_end); + uint32_t const pdo = tu_le32toh(tu_unaligned_read32(dobj)); + + switch ((pdo >> 30) & 0x03ul) { + case PD_PDO_TYPE_FIXED: { + pd_pdo_fixed_t const* fixed = (pd_pdo_fixed_t const*) &pdo; + uint32_t const voltage_mv = fixed->voltage_50mv*50; + uint32_t const current_ma = fixed->current_max_10ma*10; + printf("[Fixed] %lu mV %lu mA\r\n", voltage_mv, current_ma); + + if (voltage_mv <= VOLTAGE_MAX_MV && current_ma >= CURRENT_MAX_MA) { + // Found a suitable PDO + selected_pos = i+1; + } + + break; + } + + case PD_PDO_TYPE_BATTERY: + break; + + case PD_PDO_TYPE_VARIABLE: + break; + + case PD_PDO_TYPE_APDO: + break; + } + + dobj += 4; + } + + //------------- Response with selected PDO -------------// + // Be careful and make sure your board can withstand the selected PDO + // voltage other than safe5v e.g 12v or 20v + + printf("Selected PDO %u\r\n", selected_pos); + + // Send request with selected PDO position as response to Source Cap + pd_rdo_fixed_variable_t rdo = { + .current_extremum_10ma = 50, // max 500mA + .current_operate_10ma = 30, // 300mA + .reserved = 0, + .epr_mode_capable = 0, + .unchunked_ext_msg_support = 0, + .no_usb_suspend = 0, + .usb_comm_capable = 1, + .capability_mismatch = 0, + .give_back_flag = 0, // exteremum is max + .object_position = selected_pos, + }; + tuc_msg_request(rhport, &rdo); + + break; + } + + default: break; + } + + return true; +} + +bool tuc_pd_control_received_cb(uint8_t rhport, pd_header_t const* header) { + switch (header->msg_type) { + case PD_CTRL_ACCEPT: + printf("PD Request Accepted\r\n"); + // preparing for power transition + break; + + case PD_CTRL_REJECT: + printf("PD Request Rejected\r\n"); + // try to negotiate further power + break; + + case PD_CTRL_PS_READY: + printf("PD Power Ready\r\n"); + // Source is ready to supply power + break; + + default: + break; + } + + return true; +} + +//--------------------------------------------------------------------+ +// BLINKING TASK +//--------------------------------------------------------------------+ +void led_blinking_task(void) +{ + static uint32_t start_ms = 0; + static bool led_state = false; + + // Blink every interval ms + if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time + start_ms += blink_interval_ms; + + board_led_write(led_state); + led_state = 1 - led_state; // toggle +} diff --git a/examples/typec/power_delivery/src/tusb_config.h b/examples/typec/power_delivery/src/tusb_config.h new file mode 100644 index 000000000..deddcbfa4 --- /dev/null +++ b/examples/typec/power_delivery/src/tusb_config.h @@ -0,0 +1,79 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef _TUSB_CONFIG_H_ +#define _TUSB_CONFIG_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +// special example that doesn't enable device or host stack +// This can cause some TinyUSB API missing, this define hack to allow us to fill those API +// to pass the compilation process +#define tud_int_handler(x) + +//-------------------------------------------------------------------- +// COMMON CONFIGURATION +//-------------------------------------------------------------------- + +// defined by compiler flags for flexibility +#ifndef CFG_TUSB_MCU + #error CFG_TUSB_MCU must be defined +#endif + +#ifndef CFG_TUSB_OS + #define CFG_TUSB_OS OPT_OS_NONE +#endif + +#define CFG_TUD_ENABLED 0 +#define CFG_TUH_ENABLED 0 + +// Enable TYPEC stack +#define CFG_TUC_ENABLED 1 + +// CFG_TUSB_DEBUG is defined by compiler in DEBUG build +// #define CFG_TUSB_DEBUG 0 + +/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. + * Tinyusb use follows macros to declare transferring memory so that they can be put + * into those specific section. + * e.g + * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) + * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) + */ +#ifndef CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_SECTION +#endif + +#ifndef CFG_TUSB_MEM_ALIGN +#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) +#endif + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CONFIG_H_ */ diff --git a/hw/bsp/board.c b/hw/bsp/board.c index 66ffcb199..7804a18e0 100644 --- a/hw/bsp/board.c +++ b/hw/bsp/board.c @@ -71,11 +71,12 @@ TU_ATTR_USED int sys_write (int fhdl, const void *buf, size_t count) { (void) fhdl; uint8_t const* buf8 = (uint8_t const*) buf; - for(size_t i=0; i.map" ) endif() + + # LOGGER + if (DEFINED LOGGER) + target_compile_definitions(${TARGET} PUBLIC LOGGER_${LOGGER}) + if(LOGGER STREQUAL "RTT" OR LOGGER STREQUAL "rtt") + family_add_segger_rtt(${TARGET}) + endif () + endif () + endfunction() @@ -137,12 +158,11 @@ function(family_add_tinyusb TARGET OPT_MCU) set(TINYUSB_TARGET_PREFIX ${TARGET}-) add_library(${TARGET}-tinyusb_config INTERFACE) - target_include_directories(${TARGET}-tinyusb_config INTERFACE - ${CMAKE_CURRENT_SOURCE_DIR}/src - ) - target_compile_definitions(${TARGET}-tinyusb_config INTERFACE - CFG_TUSB_MCU=${OPT_MCU} - ) + target_include_directories(${TARGET}-tinyusb_config INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/src) + target_compile_definitions(${TARGET}-tinyusb_config INTERFACE CFG_TUSB_MCU=${OPT_MCU}) + if (DEFINED LOG) + target_compile_definitions(${TARGET}-tinyusb_config INTERFACE CFG_TUSB_DEBUG=${LOG}) + endif() # tinyusb's CMakeList.txt add_subdirectory(${TOP}/src ${CMAKE_CURRENT_BINARY_DIR}/tinyusb) diff --git a/hw/bsp/stm32g4/boards/b_g474e_dpow1/board.h b/hw/bsp/stm32g4/boards/b_g474e_dpow1/board.h index 5d936d009..e61b13170 100644 --- a/hw/bsp/stm32g4/boards/b_g474e_dpow1/board.h +++ b/hw/bsp/stm32g4/boards/b_g474e_dpow1/board.h @@ -57,6 +57,8 @@ //--------------------------------------------------------------------+ // RCC Clock //--------------------------------------------------------------------+ + +// CPU Frequency (Core Clock) is 170 MHz static inline void board_clock_init(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; @@ -66,16 +68,16 @@ static inline void board_clock_init(void) HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST); /* Activate PLL with HSI as source */ - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; - RCC_OscInitStruct.HSIState = RCC_HSI_ON; - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; - RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV4; - RCC_OscInitStruct.PLL.PLLN = 85; - RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV10; - RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; - RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; + RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV4; + RCC_OscInitStruct.PLL.PLLN = 85; + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV10; + RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; + RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; HAL_RCC_OscConfig(&RCC_OscInitStruct); // Initializes the CPU, AHB and APB buses clocks diff --git a/hw/bsp/stm32g4/boards/b_g474e_dpow1/cubemx/board.ioc b/hw/bsp/stm32g4/boards/b_g474e_dpow1/cubemx/board.ioc new file mode 100644 index 000000000..6ce126f84 --- /dev/null +++ b/hw/bsp/stm32g4/boards/b_g474e_dpow1/cubemx/board.ioc @@ -0,0 +1,194 @@ +#MicroXplorer Configuration settings - do not modify +CAD.formats= +CAD.pinconfig= +CAD.provider= +Dma.Request0=UCPD1_RX +Dma.Request1=UCPD1_TX +Dma.RequestsNb=2 +Dma.UCPD1_RX.0.Direction=DMA_PERIPH_TO_MEMORY +Dma.UCPD1_RX.0.EventEnable=DISABLE +Dma.UCPD1_RX.0.Instance=DMA1_Channel1 +Dma.UCPD1_RX.0.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.UCPD1_RX.0.MemInc=DMA_MINC_ENABLE +Dma.UCPD1_RX.0.Mode=DMA_NORMAL +Dma.UCPD1_RX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.UCPD1_RX.0.PeriphInc=DMA_PINC_DISABLE +Dma.UCPD1_RX.0.Polarity=HAL_DMAMUX_REQ_GEN_RISING +Dma.UCPD1_RX.0.Priority=DMA_PRIORITY_HIGH +Dma.UCPD1_RX.0.RequestNumber=1 +Dma.UCPD1_RX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber +Dma.UCPD1_RX.0.SignalID=NONE +Dma.UCPD1_RX.0.SyncEnable=DISABLE +Dma.UCPD1_RX.0.SyncPolarity=HAL_DMAMUX_SYNC_NO_EVENT +Dma.UCPD1_RX.0.SyncRequestNumber=1 +Dma.UCPD1_RX.0.SyncSignalID=NONE +Dma.UCPD1_TX.1.Direction=DMA_MEMORY_TO_PERIPH +Dma.UCPD1_TX.1.EventEnable=DISABLE +Dma.UCPD1_TX.1.Instance=DMA1_Channel2 +Dma.UCPD1_TX.1.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.UCPD1_TX.1.MemInc=DMA_MINC_ENABLE +Dma.UCPD1_TX.1.Mode=DMA_NORMAL +Dma.UCPD1_TX.1.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.UCPD1_TX.1.PeriphInc=DMA_PINC_DISABLE +Dma.UCPD1_TX.1.Polarity=HAL_DMAMUX_REQ_GEN_RISING +Dma.UCPD1_TX.1.Priority=DMA_PRIORITY_HIGH +Dma.UCPD1_TX.1.RequestNumber=1 +Dma.UCPD1_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber +Dma.UCPD1_TX.1.SignalID=NONE +Dma.UCPD1_TX.1.SyncEnable=DISABLE +Dma.UCPD1_TX.1.SyncPolarity=HAL_DMAMUX_SYNC_NO_EVENT +Dma.UCPD1_TX.1.SyncRequestNumber=1 +Dma.UCPD1_TX.1.SyncSignalID=NONE +File.Version=6 +GPIO.groupedBy=Group By Peripherals +KeepUserPlacement=true +Mcu.CPN=STM32G474RET3 +Mcu.Family=STM32G4 +Mcu.IP0=DMA +Mcu.IP1=NVIC +Mcu.IP2=RCC +Mcu.IP3=SYS +Mcu.IP4=UCPD1 +Mcu.IP5=USART3 +Mcu.IPNb=6 +Mcu.Name=STM32G474R(B-C-E)Tx +Mcu.Package=LQFP64 +Mcu.Pin0=PC10 +Mcu.Pin1=PC11 +Mcu.Pin2=PB4 +Mcu.Pin3=PB6 +Mcu.Pin4=VP_SYS_VS_Systick +Mcu.Pin5=VP_SYS_VS_DBSignals +Mcu.PinsNb=6 +Mcu.ThirdPartyNb=0 +Mcu.UserConstants= +Mcu.UserName=STM32G474RETx +MxCube.Version=6.8.1 +MxDb.Version=DB.6.0.81 +NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:false\:true\:false\:false +NVIC.DMA1_Channel1_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true +NVIC.DMA1_Channel2_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true +NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:false\:true\:false\:false +NVIC.ForceEnableDMAVector=true +NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:false\:true\:false\:false +NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false +NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 +NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:false +NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:false +NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:false\:true\:false\:false +PB4.Mode=Sink_AllSignals +PB4.Signal=UCPD1_CC2 +PB6.Mode=Sink_AllSignals +PB6.Signal=UCPD1_CC1 +PC10.GPIOParameters=GPIO_PuPd +PC10.GPIO_PuPd=GPIO_PULLUP +PC10.Mode=Asynchronous +PC10.Signal=USART3_TX +PC11.GPIOParameters=GPIO_PuPd +PC11.GPIO_PuPd=GPIO_PULLUP +PC11.Mode=Asynchronous +PC11.Signal=USART3_RX +PinOutPanel.RotationAngle=0 +ProjectManager.AskForMigrate=true +ProjectManager.BackupPrevious=false +ProjectManager.CompilerOptimize=6 +ProjectManager.ComputerToolchain=false +ProjectManager.CoupleFile=false +ProjectManager.CustomerFirmwarePackage= +ProjectManager.DefaultFWLocation=true +ProjectManager.DeletePrevious=true +ProjectManager.DeviceId=STM32G474RETx +ProjectManager.FirmwarePackage=STM32Cube FW_G4 V1.5.1 +ProjectManager.FreePins=false +ProjectManager.HalAssertFull=false +ProjectManager.HeapSize=0x200 +ProjectManager.KeepUserCode=true +ProjectManager.LastFirmware=true +ProjectManager.LibraryCopy=2 +ProjectManager.MainLocation=Src +ProjectManager.NoMain=false +ProjectManager.PreviousToolchain= +ProjectManager.ProjectBuild=false +ProjectManager.ProjectFileName=board.ioc +ProjectManager.ProjectName=board +ProjectManager.ProjectStructure= +ProjectManager.RegisterCallBack= +ProjectManager.StackSize=0x400 +ProjectManager.TargetToolchain=Makefile +ProjectManager.ToolChainLocation= +ProjectManager.UnderRoot=false +ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_USART3_UART_Init-USART3-false-HAL-true,5-MX_UCPD1_Init-UCPD1-false-LL-true +RCC.ADC12Freq_Value=150000000 +RCC.ADC345Freq_Value=150000000 +RCC.AHBFreq_Value=150000000 +RCC.APB1Freq_Value=150000000 +RCC.APB1TimFreq_Value=150000000 +RCC.APB2Freq_Value=150000000 +RCC.APB2TimFreq_Value=150000000 +RCC.CRSFreq_Value=48000000 +RCC.CortexFreq_Value=150000000 +RCC.EXTERNAL_CLOCK_VALUE=12288000 +RCC.FCLKCortexFreq_Value=150000000 +RCC.FDCANFreq_Value=150000000 +RCC.FamilyName=M +RCC.HCLKFreq_Value=150000000 +RCC.HRTIM1Freq_Value=150000000 +RCC.HSE_VALUE=24000000 +RCC.HSI48_VALUE=48000000 +RCC.HSI_VALUE=16000000 +RCC.I2C1Freq_Value=150000000 +RCC.I2C2Freq_Value=150000000 +RCC.I2C3Freq_Value=150000000 +RCC.I2C4Freq_Value=150000000 +RCC.I2SFreq_Value=150000000 +RCC.IPParameters=ADC12Freq_Value,ADC345Freq_Value,AHBFreq_Value,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,CRSFreq_Value,CortexFreq_Value,EXTERNAL_CLOCK_VALUE,FCLKCortexFreq_Value,FDCANFreq_Value,FamilyName,HCLKFreq_Value,HRTIM1Freq_Value,HSE_VALUE,HSI48_VALUE,HSI_VALUE,I2C1Freq_Value,I2C2Freq_Value,I2C3Freq_Value,I2C4Freq_Value,I2SFreq_Value,LPTIM1Freq_Value,LPUART1Freq_Value,LSCOPinFreq_Value,LSE_VALUE,LSI_VALUE,MCO1PinFreq_Value,PLLM,PLLN,PLLPoutputFreq_Value,PLLQ,PLLQoutputFreq_Value,PLLRCLKFreq_Value,PWRFreq_Value,QSPIFreq_Value,RNGFreq_Value,SAI1Freq_Value,SYSCLKFreq_VALUE,SYSCLKSource,UART4Freq_Value,UART5Freq_Value,USART1Freq_Value,USART2Freq_Value,USART3Freq_Value,USBFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value +RCC.LPTIM1Freq_Value=150000000 +RCC.LPUART1Freq_Value=150000000 +RCC.LSCOPinFreq_Value=32000 +RCC.LSE_VALUE=32768 +RCC.LSI_VALUE=32000 +RCC.MCO1PinFreq_Value=16000000 +RCC.PLLM=RCC_PLLM_DIV4 +RCC.PLLN=75 +RCC.PLLPoutputFreq_Value=150000000 +RCC.PLLQ=RCC_PLLQ_DIV4 +RCC.PLLQoutputFreq_Value=75000000 +RCC.PLLRCLKFreq_Value=150000000 +RCC.PWRFreq_Value=150000000 +RCC.QSPIFreq_Value=150000000 +RCC.RNGFreq_Value=75000000 +RCC.SAI1Freq_Value=150000000 +RCC.SYSCLKFreq_VALUE=150000000 +RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK +RCC.UART4Freq_Value=150000000 +RCC.UART5Freq_Value=150000000 +RCC.USART1Freq_Value=150000000 +RCC.USART2Freq_Value=150000000 +RCC.USART3Freq_Value=150000000 +RCC.USBFreq_Value=75000000 +RCC.VCOInputFreq_Value=4000000 +RCC.VCOOutputFreq_Value=300000000 +USART3.AutoBaudRateEnableParam=UART_ADVFEATURE_AUTOBAUDRATE_DISABLE +USART3.BaudRate=115200 +USART3.DMADisableonRxErrorParam=ADVFEATURE_DMA_ENABLEONRXERROR +USART3.DataInvertParam=ADVFEATURE_DATAINV_DISABLE +USART3.IPParameters=BaudRate,WordLength,Parity,StopBits,Mode,OverSampling,OneBitSampling,AutoBaudRateEnableParam,TxPinLevelInvertParam,RxPinLevelInvertParam,DataInvertParam,SwapParam,OverrunDisableParam,DMADisableonRxErrorParam,MSBFirstParam,VirtualMode-Asynchronous +USART3.MSBFirstParam=ADVFEATURE_MSBFIRST_DISABLE +USART3.Mode=MODE_TX_RX +USART3.OneBitSampling=UART_ONE_BIT_SAMPLE_DISABLE +USART3.OverSampling=UART_OVERSAMPLING_16 +USART3.OverrunDisableParam=ADVFEATURE_OVERRUN_ENABLE +USART3.Parity=PARITY_ODD +USART3.RxPinLevelInvertParam=ADVFEATURE_RXINV_DISABLE +USART3.StopBits=STOPBITS_1 +USART3.SwapParam=ADVFEATURE_SWAP_DISABLE +USART3.TxPinLevelInvertParam=ADVFEATURE_TXINV_DISABLE +USART3.VirtualMode-Asynchronous=VM_ASYNC +USART3.WordLength=WORDLENGTH_8B +VP_SYS_VS_DBSignals.Mode=DisableDeadBatterySignals +VP_SYS_VS_DBSignals.Signal=SYS_VS_DBSignals +VP_SYS_VS_Systick.Mode=SysTick +VP_SYS_VS_Systick.Signal=SYS_VS_Systick +board=custom diff --git a/hw/bsp/stm32g4/family.c b/hw/bsp/stm32g4/family.c index 3b490e9b3..d77183357 100644 --- a/hw/bsp/stm32g4/family.c +++ b/hw/bsp/stm32g4/family.c @@ -25,6 +25,8 @@ */ #include "stm32g4xx_hal.h" +#include "stm32g4xx_ll_bus.h" + #include "bsp/board.h" #include "board.h" @@ -46,6 +48,11 @@ void USBWakeUp_IRQHandler(void) tud_int_handler(0); } +// USB PD +void UCPD1_IRQHandler(void) { + tuc_int_handler(0); +} + //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM //--------------------------------------------------------------------+ @@ -79,9 +86,10 @@ void board_init(void) NVIC_SetPriority(USBWakeUp_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); #endif - GPIO_InitTypeDef GPIO_InitStruct; + GPIO_InitTypeDef GPIO_InitStruct; // LED + memset(&GPIO_InitStruct, 0, sizeof(GPIO_InitStruct)); GPIO_InitStruct.Pin = LED_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; @@ -91,6 +99,7 @@ void board_init(void) board_led_write(false); // Button + memset(&GPIO_InitStruct, 0, sizeof(GPIO_InitStruct)); GPIO_InitStruct.Pin = BUTTON_PIN; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = BUTTON_STATE_ACTIVE ? GPIO_PULLDOWN : GPIO_PULLUP; @@ -99,6 +108,7 @@ void board_init(void) #ifdef UART_DEV // UART + memset(&GPIO_InitStruct, 0, sizeof(GPIO_InitStruct)); GPIO_InitStruct.Pin = UART_TX_PIN | UART_RX_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; @@ -121,6 +131,7 @@ void board_init(void) // USB Pins TODO double check USB clock and pin setup // Configure USB DM and DP pins. This is optional, and maintained only for user guidance. + memset(&GPIO_InitStruct, 0, sizeof(GPIO_InitStruct)); GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12); GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; @@ -130,6 +141,21 @@ void board_init(void) __HAL_RCC_USB_CLK_ENABLE(); board_vbus_sense_init(); + +#if 1 + // USB PD + // Default CC1/CC2 is PB4/PB6 + + // Enable pwr for disabling dead battery feature in Power's CR3 + __HAL_RCC_PWR_CLK_ENABLE(); + __HAL_RCC_CRC_CLK_ENABLE(); + __HAL_RCC_UCPD1_CLK_ENABLE(); + + // Enable DMA for USB PD + __HAL_RCC_DMAMUX1_CLK_ENABLE(); + __HAL_RCC_DMA1_CLK_ENABLE(); +#endif + } //--------------------------------------------------------------------+ diff --git a/hw/bsp/stm32g4/family.cmake b/hw/bsp/stm32g4/family.cmake index ab17c0980..618563f66 100644 --- a/hw/bsp/stm32g4/family.cmake +++ b/hw/bsp/stm32g4/family.cmake @@ -90,6 +90,7 @@ function(family_configure_example TARGET) target_sources(${TARGET} PUBLIC # TinyUSB Port ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/typec/typec_stm32.c # BSP ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c @@ -109,7 +110,7 @@ function(family_configure_example TARGET) # Flashing family_flash_stlink(${TARGET}) - #family_flash_jlink(${TARGET}) + family_flash_jlink(${TARGET}) endfunction() diff --git a/lib/SEGGER_RTT/RTT/SEGGER_RTT_Conf.h b/lib/SEGGER_RTT/Config/SEGGER_RTT_Conf.h similarity index 69% rename from lib/SEGGER_RTT/RTT/SEGGER_RTT_Conf.h rename to lib/SEGGER_RTT/Config/SEGGER_RTT_Conf.h index fda5a5f51..3ac38dcf1 100644 --- a/lib/SEGGER_RTT/RTT/SEGGER_RTT_Conf.h +++ b/lib/SEGGER_RTT/Config/SEGGER_RTT_Conf.h @@ -3,7 +3,7 @@ * The Embedded Experts * ********************************************************************** * * -* (c) 1995 - 2019 SEGGER Microcontroller GmbH * +* (c) 1995 - 2020 SEGGER Microcontroller GmbH * * * * www.segger.com Support: support@segger.com * * * @@ -46,7 +46,7 @@ File : SEGGER_RTT_Conf.h Purpose : Implementation of SEGGER real-time transfer (RTT) which allows real-time communication on targets which support debugger memory accesses while the CPU is running. -Revision: $Rev: 18601 $ +Revision: $Rev: 24316 $ */ @@ -63,10 +63,25 @@ Revision: $Rev: 18601 $ * ********************************************************************** */ + +// +// Take in and set to correct values for Cortex-A systems with CPU cache +// +//#define SEGGER_RTT_CPU_CACHE_LINE_SIZE (32) // Largest cache line size (in bytes) in the current system +//#define SEGGER_RTT_UNCACHED_OFF (0xFB000000) // Address alias where RTT CB and buffers can be accessed uncached +// +// Most common case: +// Up-channel 0: RTT +// Up-channel 1: SystemView +// #ifndef SEGGER_RTT_MAX_NUM_UP_BUFFERS #define SEGGER_RTT_MAX_NUM_UP_BUFFERS (3) // Max. number of up-buffers (T->H) available on this target (Default: 3) #endif - +// +// Most common case: +// Down-channel 0: RTT +// Down-channel 1: SystemView +// #ifndef SEGGER_RTT_MAX_NUM_DOWN_BUFFERS #define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (3) // Max. number of down-buffers (H->T) available on this target (Default: 3) #endif @@ -135,18 +150,18 @@ Revision: $Rev: 18601 $ #if ((defined(__SES_ARM) || defined(__SES_RISCV) || defined(__CROSSWORKS_ARM) || defined(__GNUC__) || defined(__clang__)) && !defined (__CC_ARM) && !defined(WIN32)) #if (defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_8M_BASE__)) #define SEGGER_RTT_LOCK() { \ - unsigned int LockState; \ + unsigned int _SEGGER_RTT__LockState; \ __asm volatile ("mrs %0, primask \n\t" \ - "movs r1, $1 \n\t" \ + "movs r1, #1 \n\t" \ "msr primask, r1 \n\t" \ - : "=r" (LockState) \ + : "=r" (_SEGGER_RTT__LockState) \ : \ - : "r1" \ + : "r1", "cc" \ ); #define SEGGER_RTT_UNLOCK() __asm volatile ("msr primask, %0 \n\t" \ : \ - : "r" (LockState) \ + : "r" (_SEGGER_RTT__LockState) \ : \ ); \ } @@ -155,32 +170,32 @@ Revision: $Rev: 18601 $ #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) #endif #define SEGGER_RTT_LOCK() { \ - unsigned int LockState; \ + unsigned int _SEGGER_RTT__LockState; \ __asm volatile ("mrs %0, basepri \n\t" \ "mov r1, %1 \n\t" \ "msr basepri, r1 \n\t" \ - : "=r" (LockState) \ + : "=r" (_SEGGER_RTT__LockState) \ : "i"(SEGGER_RTT_MAX_INTERRUPT_PRIORITY) \ - : "r1" \ + : "r1", "cc" \ ); #define SEGGER_RTT_UNLOCK() __asm volatile ("msr basepri, %0 \n\t" \ : \ - : "r" (LockState) \ + : "r" (_SEGGER_RTT__LockState) \ : \ ); \ } - #elif defined(__ARM_ARCH_7A__) + #elif (defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__)) #define SEGGER_RTT_LOCK() { \ - unsigned int LockState; \ + unsigned int _SEGGER_RTT__LockState; \ __asm volatile ("mrs r1, CPSR \n\t" \ "mov %0, r1 \n\t" \ "orr r1, r1, #0xC0 \n\t" \ "msr CPSR_c, r1 \n\t" \ - : "=r" (LockState) \ + : "=r" (_SEGGER_RTT__LockState) \ : \ - : "r1" \ + : "r1", "cc" \ ); #define SEGGER_RTT_UNLOCK() __asm volatile ("mov r0, %0 \n\t" \ @@ -190,17 +205,17 @@ Revision: $Rev: 18601 $ "orr r1, r1, r0 \n\t" \ "msr CPSR_c, r1 \n\t" \ : \ - : "r" (LockState) \ - : "r0", "r1" \ + : "r" (_SEGGER_RTT__LockState) \ + : "r0", "r1", "cc" \ ); \ } #elif defined(__riscv) || defined(__riscv_xlen) #define SEGGER_RTT_LOCK() { \ - unsigned int LockState; \ + unsigned int _SEGGER_RTT__LockState; \ __asm volatile ("csrr %0, mstatus \n\t" \ "csrci mstatus, 8 \n\t" \ "andi %0, %0, 8 \n\t" \ - : "=r" (LockState) \ + : "=r" (_SEGGER_RTT__LockState) \ : \ : \ ); @@ -209,7 +224,7 @@ Revision: $Rev: 18601 $ "or %0, %0, a1 \n\t" \ "csrs mstatus, %0 \n\t" \ : \ - : "r" (LockState) \ + : "r" (_SEGGER_RTT__LockState) \ : "a1" \ ); \ } @@ -227,11 +242,11 @@ Revision: $Rev: 18601 $ #if (defined (__ARM6M__) && (__CORE__ == __ARM6M__)) || \ (defined (__ARM8M_BASELINE__) && (__CORE__ == __ARM8M_BASELINE__)) #define SEGGER_RTT_LOCK() { \ - unsigned int LockState; \ - LockState = __get_PRIMASK(); \ + unsigned int _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_PRIMASK(); \ __set_PRIMASK(1); - #define SEGGER_RTT_UNLOCK() __set_PRIMASK(LockState); \ + #define SEGGER_RTT_UNLOCK() __set_PRIMASK(_SEGGER_RTT__LockState); \ } #elif (defined (__ARM7EM__) && (__CORE__ == __ARM7EM__)) || \ (defined (__ARM7M__) && (__CORE__ == __ARM7M__)) || \ @@ -241,12 +256,36 @@ Revision: $Rev: 18601 $ #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) #endif #define SEGGER_RTT_LOCK() { \ - unsigned int LockState; \ - LockState = __get_BASEPRI(); \ + unsigned int _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_BASEPRI(); \ __set_BASEPRI(SEGGER_RTT_MAX_INTERRUPT_PRIORITY); - #define SEGGER_RTT_UNLOCK() __set_BASEPRI(LockState); \ + #define SEGGER_RTT_UNLOCK() __set_BASEPRI(_SEGGER_RTT__LockState); \ } + #elif (defined (__ARM7A__) && (__CORE__ == __ARM7A__)) || \ + (defined (__ARM7R__) && (__CORE__ == __ARM7R__)) + #define SEGGER_RTT_LOCK() { \ + unsigned int _SEGGER_RTT__LockState; \ + __asm volatile ("mrs r1, CPSR \n\t" \ + "mov %0, r1 \n\t" \ + "orr r1, r1, #0xC0 \n\t" \ + "msr CPSR_c, r1 \n\t" \ + : "=r" (_SEGGER_RTT__LockState) \ + : \ + : "r1", "cc" \ + ); + + #define SEGGER_RTT_UNLOCK() __asm volatile ("mov r0, %0 \n\t" \ + "mrs r1, CPSR \n\t" \ + "bic r1, r1, #0xC0 \n\t" \ + "and r0, r0, #0xC0 \n\t" \ + "orr r1, r1, r0 \n\t" \ + "msr CPSR_c, r1 \n\t" \ + : \ + : "r" (_SEGGER_RTT__LockState) \ + : "r0", "r1", "cc" \ + ); \ + } #endif #endif @@ -256,11 +295,11 @@ Revision: $Rev: 18601 $ */ #ifdef __ICCRX__ #define SEGGER_RTT_LOCK() { \ - unsigned long LockState; \ - LockState = __get_interrupt_state(); \ + unsigned long _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_interrupt_state(); \ __disable_interrupt(); - #define SEGGER_RTT_UNLOCK() __set_interrupt_state(LockState); \ + #define SEGGER_RTT_UNLOCK() __set_interrupt_state(_SEGGER_RTT__LockState); \ } #endif @@ -270,11 +309,11 @@ Revision: $Rev: 18601 $ */ #ifdef __ICCRL78__ #define SEGGER_RTT_LOCK() { \ - __istate_t LockState; \ - LockState = __get_interrupt_state(); \ + __istate_t _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_interrupt_state(); \ __disable_interrupt(); - #define SEGGER_RTT_UNLOCK() __set_interrupt_state(LockState); \ + #define SEGGER_RTT_UNLOCK() __set_interrupt_state(_SEGGER_RTT__LockState); \ } #endif @@ -285,13 +324,13 @@ Revision: $Rev: 18601 $ #ifdef __CC_ARM #if (defined __TARGET_ARCH_6S_M) #define SEGGER_RTT_LOCK() { \ - unsigned int LockState; \ - register unsigned char PRIMASK __asm( "primask"); \ - LockState = PRIMASK; \ - PRIMASK = 1u; \ + unsigned int _SEGGER_RTT__LockState; \ + register unsigned char _SEGGER_RTT__PRIMASK __asm( "primask"); \ + _SEGGER_RTT__LockState = _SEGGER_RTT__PRIMASK; \ + _SEGGER_RTT__PRIMASK = 1u; \ __schedule_barrier(); - #define SEGGER_RTT_UNLOCK() PRIMASK = LockState; \ + #define SEGGER_RTT_UNLOCK() _SEGGER_RTT__PRIMASK = _SEGGER_RTT__LockState; \ __schedule_barrier(); \ } #elif (defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M)) @@ -299,13 +338,13 @@ Revision: $Rev: 18601 $ #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) #endif #define SEGGER_RTT_LOCK() { \ - unsigned int LockState; \ + unsigned int _SEGGER_RTT__LockState; \ register unsigned char BASEPRI __asm( "basepri"); \ - LockState = BASEPRI; \ + _SEGGER_RTT__LockState = BASEPRI; \ BASEPRI = SEGGER_RTT_MAX_INTERRUPT_PRIORITY; \ __schedule_barrier(); - #define SEGGER_RTT_UNLOCK() BASEPRI = LockState; \ + #define SEGGER_RTT_UNLOCK() BASEPRI = _SEGGER_RTT__LockState; \ __schedule_barrier(); \ } #endif @@ -318,21 +357,21 @@ Revision: $Rev: 18601 $ #ifdef __TI_ARM__ #if defined (__TI_ARM_V6M0__) #define SEGGER_RTT_LOCK() { \ - unsigned int LockState; \ - LockState = __get_PRIMASK(); \ + unsigned int _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_PRIMASK(); \ __set_PRIMASK(1); - #define SEGGER_RTT_UNLOCK() __set_PRIMASK(LockState); \ + #define SEGGER_RTT_UNLOCK() __set_PRIMASK(_SEGGER_RTT__LockState); \ } #elif (defined (__TI_ARM_V7M3__) || defined (__TI_ARM_V7M4__)) #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) #endif #define SEGGER_RTT_LOCK() { \ - unsigned int LockState; \ - LockState = _set_interrupt_priority(SEGGER_RTT_MAX_INTERRUPT_PRIORITY); + unsigned int _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = _set_interrupt_priority(SEGGER_RTT_MAX_INTERRUPT_PRIORITY); - #define SEGGER_RTT_UNLOCK() _set_interrupt_priority(LockState); \ + #define SEGGER_RTT_UNLOCK() _set_interrupt_priority(_SEGGER_RTT__LockState); \ } #endif #endif @@ -342,12 +381,13 @@ Revision: $Rev: 18601 $ * RTT lock configuration for CCRX */ #ifdef __RX + #include #define SEGGER_RTT_LOCK() { \ - unsigned long LockState; \ - LockState = get_psw() & 0x010000; \ + unsigned long _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = get_psw() & 0x010000; \ clrpsw_i(); - #define SEGGER_RTT_UNLOCK() set_psw(get_psw() | LockState); \ + #define SEGGER_RTT_UNLOCK() set_psw(get_psw() | _SEGGER_RTT__LockState); \ } #endif diff --git a/lib/SEGGER_RTT/LICENSE.md b/lib/SEGGER_RTT/LICENSE.md new file mode 100644 index 000000000..14881c29b --- /dev/null +++ b/lib/SEGGER_RTT/LICENSE.md @@ -0,0 +1,36 @@ + + SEGGER Microcontroller GmbH + The Embedded Experts + + (c) 1995 - 2021 SEGGER Microcontroller GmbH + www.segger.com Support: support@segger.com + + SEGGER RTT Real Time Transfer for embedded targets + + + All rights reserved. + + SEGGER strongly recommends to not make any changes + to or modify the source code of this software in order to stay + compatible with the RTT protocol and J-Link. + + Redistribution and use in source and binary forms, with or + without modification, are permitted provided that the following + condition is met: + + - Redistributions of source code must retain the above copyright + notice, this condition and the following disclaimer. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. diff --git a/lib/SEGGER_RTT/License.txt b/lib/SEGGER_RTT/License.txt deleted file mode 100644 index e1f5f89ff..000000000 --- a/lib/SEGGER_RTT/License.txt +++ /dev/null @@ -1,34 +0,0 @@ -Important - Read carefully: - -SEGGER RTT - Real Time Transfer for embedded targets - -All rights reserved. - -SEGGER strongly recommends to not make any changes -to or modify the source code of this software in order to stay -compatible with the RTT protocol and J-Link. - -Redistribution and use in source and binary forms, with or -without modification, are permitted provided that the following -condition is met: - -o Redistributions of source code must retain the above copyright - notice, this condition and the following disclaimer. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. - - -(c) 2014 - 2016 SEGGER Microcontroller GmbH -www.segger.com diff --git a/lib/SEGGER_RTT/README.md b/lib/SEGGER_RTT/README.md new file mode 100644 index 000000000..06349d248 --- /dev/null +++ b/lib/SEGGER_RTT/README.md @@ -0,0 +1,24 @@ +RTT +=== + +SEGGER RTT Sources + +https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer +https://wiki.segger.com/RTT + +## Included files + + * `RTT/` + * `SEGGER_RTT.c` - Main module for RTT. + * `SEGGER_RTT.h` - Main header for RTT. + * `SEGGER_RTT_ASM_ARMv7M.S` - Assembly-optimized implementation of RTT functions for ARMv7M processors. + * `SEGGER_RTT_Printf.c` - Simple implementation of printf (`SEGGER_RTT_Printf()`) to write formatted strings via RTT. + * `Syscalls/` + * `SEGGER_RTT_Syscalls_*.c` - Low-level syscalls to retarget `printf()` to RTT with different toolchains. + * `Config/` + * `SEGGER_RTT_Conf.h` - RTT configuration file. + * `Examples/` + * `Main_RTT_InputEchoApp.c` - Example application which echoes input on Channel 0. + * `Main_RTT_MenuApp.c` - Example application to demonstrate RTT bi-directional functionality. + * `Main_RTT_PrintfTest.c` - Example application to test RTT's simple printf implementation. + * `Main_RTT_SpeedTestApp.c` - Example application to measure RTT performance. (Requires embOS) diff --git a/lib/SEGGER_RTT/README.txt b/lib/SEGGER_RTT/README.txt deleted file mode 100644 index 49ec655c4..000000000 --- a/lib/SEGGER_RTT/README.txt +++ /dev/null @@ -1,20 +0,0 @@ -README.txt for the SEGGER RTT Implementation Pack. - -Included files: -=============== -Root Directory - - Examples - - Main_RTT_InputEchoApp.c - Sample application which echoes input on Channel 0. - - Main_RTT_MenuApp.c - Sample application to demonstrate RTT bi-directional functionality. - - Main_RTT_PrintfTest.c - Sample application to test RTT small printf implementation. - - Main_RTT_SpeedTestApp.c - Sample application for measuring RTT performance. embOS needed. - - RTT - - SEGGER_RTT.c - The RTT implementation. - - SEGGER_RTT.h - Header for RTT implementation. - - SEGGER_RTT_Conf.h - Pre-processor configuration for the RTT implementation. - - SEGGER_RTT_Printf.c - Simple implementation of printf to write formatted strings via RTT. - - Syscalls - - RTT_Syscalls_GCC.c - Low-level syscalls to retarget printf() to RTT with GCC / Newlib. - - RTT_Syscalls_IAR.c - Low-level syscalls to retarget printf() to RTT with IAR compiler. - - RTT_Syscalls_KEIL.c - Low-level syscalls to retarget printf() to RTT with KEIL/uVision compiler. - - RTT_Syscalls_SES.c - Low-level syscalls to retarget printf() to RTT with SEGGER Embedded Studio. diff --git a/lib/SEGGER_RTT/RTT/SEGGER_RTT.c b/lib/SEGGER_RTT/RTT/SEGGER_RTT.c index c8de8e0f3..895085ba2 100644 --- a/lib/SEGGER_RTT/RTT/SEGGER_RTT.c +++ b/lib/SEGGER_RTT/RTT/SEGGER_RTT.c @@ -46,7 +46,7 @@ File : SEGGER_RTT.c Purpose : Implementation of SEGGER real-time transfer (RTT) which allows real-time communication on targets which support debugger memory accesses while the CPU is running. -Revision: $Rev: 17697 $ +Revision: $Rev: 29668 $ Additional information: Type "int" is assumed to be 32-bits in size @@ -80,6 +80,27 @@ Additional information: ********************************************************************** */ +#if SEGGER_RTT_CPU_CACHE_LINE_SIZE + #ifdef SEGGER_RTT_CB_ALIGN + #error "Custom SEGGER_RTT_CB_ALIGN() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif + #ifdef SEGGER_RTT_BUFFER_ALIGN + #error "Custom SEGGER_RTT_BUFFER_ALIGN() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif + #ifdef SEGGER_RTT_PUT_CB_SECTION + #error "Custom SEGGER_RTT_PUT_CB_SECTION() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif + #ifdef SEGGER_RTT_PUT_BUFFER_SECTION + #error "Custom SEGGER_RTT_PUT_BUFFER_SECTION() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif + #ifdef SEGGER_RTT_BUFFER_ALIGNMENT + #error "Custom SEGGER_RTT_BUFFER_ALIGNMENT is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif + #ifdef SEGGER_RTT_ALIGNMENT + #error "Custom SEGGER_RTT_ALIGNMENT is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif +#endif + #ifndef BUFFER_SIZE_UP #define BUFFER_SIZE_UP 1024 // Size of the buffer for terminal output of target, up to host #endif @@ -103,11 +124,11 @@ Additional information: #endif #ifndef SEGGER_RTT_ALIGNMENT - #define SEGGER_RTT_ALIGNMENT 0 + #define SEGGER_RTT_ALIGNMENT SEGGER_RTT_CPU_CACHE_LINE_SIZE #endif #ifndef SEGGER_RTT_BUFFER_ALIGNMENT - #define SEGGER_RTT_BUFFER_ALIGNMENT 0 + #define SEGGER_RTT_BUFFER_ALIGNMENT SEGGER_RTT_CPU_CACHE_LINE_SIZE #endif #ifndef SEGGER_RTT_MODE_DEFAULT @@ -127,7 +148,7 @@ Additional information: #endif #ifndef STRCPY - #define STRCPY(pDest, pSrc, NumBytes) strcpy((pDest), (pSrc)) + #define STRCPY(pDest, pSrc) strcpy((pDest), (pSrc)) #endif #ifndef SEGGER_RTT_MEMCPY_USE_BYTELOOP @@ -143,17 +164,17 @@ Additional information: #endif #ifndef MIN - #define MIN(a, b) (((a) < (b)) ? (a) : (b)) + #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif #ifndef MAX - #define MAX(a, b) (((a) > (b)) ? (a) : (b)) + #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif // // For some environments, NULL may not be defined until certain headers are included // #ifndef NULL - #define NULL 0 + #define NULL 0 #endif /********************************************************************* @@ -167,7 +188,7 @@ Additional information: #endif #if SEGGER_RTT_ALIGNMENT || SEGGER_RTT_BUFFER_ALIGNMENT - #if (defined __GNUC__) + #if ((defined __GNUC__) || (defined __clang__)) #define SEGGER_RTT_ALIGN(Var, Alignment) Var __attribute__ ((aligned (Alignment))) #elif (defined __ICCARM__) || (defined __ICCRX__) #define PRAGMA(A) _Pragma(#A) @@ -183,7 +204,7 @@ Additional information: #endif #if defined(SEGGER_RTT_SECTION) || defined (SEGGER_RTT_BUFFER_SECTION) - #if (defined __GNUC__) + #if ((defined __GNUC__) || (defined __clang__)) #define SEGGER_RTT_PUT_SECTION(Var, Section) __attribute__ ((section (Section))) Var #elif (defined __ICCARM__) || (defined __ICCRX__) #define SEGGER_RTT_PUT_SECTION(Var, Section) RTT_PRAGMA(location=Section) \ @@ -197,7 +218,6 @@ Additional information: #define SEGGER_RTT_PUT_SECTION(Var, Section) Var #endif - #if SEGGER_RTT_ALIGNMENT #define SEGGER_RTT_CB_ALIGN(Var) SEGGER_RTT_ALIGN(Var, SEGGER_RTT_ALIGNMENT) #else @@ -230,7 +250,7 @@ Additional information: ********************************************************************** */ -static unsigned char _aTerminalId[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; +static const unsigned char _aTerminalId[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; /********************************************************************* * @@ -238,13 +258,30 @@ static unsigned char _aTerminalId[16] = { '0', '1', '2', '3', '4', '5', '6', '7' * ********************************************************************** */ + // // RTT Control Block and allocate buffers for channel 0 // -SEGGER_RTT_PUT_CB_SECTION(SEGGER_RTT_CB_ALIGN(SEGGER_RTT_CB _SEGGER_RTT)); - -SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acUpBuffer [BUFFER_SIZE_UP])); -SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acDownBuffer[BUFFER_SIZE_DOWN])); +#if SEGGER_RTT_CPU_CACHE_LINE_SIZE + #if ((defined __GNUC__) || (defined __clang__)) + SEGGER_RTT_CB _SEGGER_RTT __attribute__ ((aligned (SEGGER_RTT_CPU_CACHE_LINE_SIZE))); + static char _acUpBuffer [SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_UP)] __attribute__ ((aligned (SEGGER_RTT_CPU_CACHE_LINE_SIZE))); + static char _acDownBuffer[SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_DOWN)] __attribute__ ((aligned (SEGGER_RTT_CPU_CACHE_LINE_SIZE))); + #elif (defined __ICCARM__) + #pragma data_alignment=SEGGER_RTT_CPU_CACHE_LINE_SIZE + SEGGER_RTT_CB _SEGGER_RTT; + #pragma data_alignment=SEGGER_RTT_CPU_CACHE_LINE_SIZE + static char _acUpBuffer [SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_UP)]; + #pragma data_alignment=SEGGER_RTT_CPU_CACHE_LINE_SIZE + static char _acDownBuffer[SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_DOWN)]; + #else + #error "Don't know how to place _SEGGER_RTT, _acUpBuffer, _acDownBuffer cache-line aligned" + #endif +#else + SEGGER_RTT_PUT_CB_SECTION(SEGGER_RTT_CB_ALIGN(SEGGER_RTT_CB _SEGGER_RTT)); + SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acUpBuffer [BUFFER_SIZE_UP])); + SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acDownBuffer[BUFFER_SIZE_DOWN])); +#endif static unsigned char _ActiveTerminal; @@ -261,18 +298,29 @@ static unsigned char _ActiveTerminal; * * Function description * Initializes the control block an buffers. -* May only be called via INIT() to avoid overriding settings. * +* Notes +* (1) May only be called via INIT() to avoid overriding settings. +* The only exception is SEGGER_RTT_Init(), to make an intentional override possible. */ -#define INIT() do { \ - if (_SEGGER_RTT.acID[0] == '\0') { _DoInit(); } \ - } while (0) + #define INIT() \ + do { \ + volatile SEGGER_RTT_CB* pRTTCBInit; \ + pRTTCBInit = (volatile SEGGER_RTT_CB*)((char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); \ + if (pRTTCBInit->acID[0] != 'S') { \ + _DoInit(); \ + } \ + } while (0) + static void _DoInit(void) { - SEGGER_RTT_CB* p; + volatile SEGGER_RTT_CB* p; // Volatile to make sure that compiler cannot change the order of accesses to the control block + static const char _aInitStr[] = "\0\0\0\0\0\0TTR REGGES"; // Init complete ID string to make sure that things also work if RTT is linked to a no-init memory area + unsigned i; // // Initialize control block // - p = &_SEGGER_RTT; + p = (volatile SEGGER_RTT_CB*)((char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access control block uncached so that nothing in the cache ever becomes dirty and all changes are visible in HW directly + memset((SEGGER_RTT_CB*)p, 0, sizeof(_SEGGER_RTT)); // Make sure that the RTT CB is always zero initialized. p->MaxNumUpBuffers = SEGGER_RTT_MAX_NUM_UP_BUFFERS; p->MaxNumDownBuffers = SEGGER_RTT_MAX_NUM_DOWN_BUFFERS; // @@ -280,7 +328,7 @@ static void _DoInit(void) { // p->aUp[0].sName = "Terminal"; p->aUp[0].pBuffer = _acUpBuffer; - p->aUp[0].SizeOfBuffer = sizeof(_acUpBuffer); + p->aUp[0].SizeOfBuffer = BUFFER_SIZE_UP; p->aUp[0].RdOff = 0u; p->aUp[0].WrOff = 0u; p->aUp[0].Flags = SEGGER_RTT_MODE_DEFAULT; @@ -289,18 +337,20 @@ static void _DoInit(void) { // p->aDown[0].sName = "Terminal"; p->aDown[0].pBuffer = _acDownBuffer; - p->aDown[0].SizeOfBuffer = sizeof(_acDownBuffer); + p->aDown[0].SizeOfBuffer = BUFFER_SIZE_DOWN; p->aDown[0].RdOff = 0u; p->aDown[0].WrOff = 0u; p->aDown[0].Flags = SEGGER_RTT_MODE_DEFAULT; // // Finish initialization of the control block. - // Copy Id string in three steps to make sure "SEGGER RTT" is not found - // in initializer memory (usually flash) by J-Link + // Copy Id string backwards to make sure that "SEGGER RTT" is not found in initializer memory (usually flash), + // as this would cause J-Link to "find" the control block at a wrong address. // - STRCPY(&p->acID[7], "RTT", 9); - STRCPY(&p->acID[0], "SEGGER", 7); - p->acID[6] = ' '; + RTT__DMB(); // Force order of memory accesses for cores that may perform out-of-order memory accesses + for (i = 0; i < sizeof(_aInitStr) - 1; ++i) { + p->acID[i] = _aInitStr[sizeof(_aInitStr) - 2 - i]; // Skip terminating \0 at the end of the array + } + RTT__DMB(); // Force order of memory accesses for cores that may perform out-of-order memory accesses } /********************************************************************* @@ -327,9 +377,7 @@ static unsigned _WriteBlocking(SEGGER_RTT_BUFFER_UP* pRing, const char* pBuffer, unsigned NumBytesWritten; unsigned RdOff; unsigned WrOff; -#if SEGGER_RTT_MEMCPY_USE_BYTELOOP - char* pDst; -#endif + volatile char* pDst; // // Write data to buffer and handle wrap-around if necessary // @@ -344,8 +392,8 @@ static unsigned _WriteBlocking(SEGGER_RTT_BUFFER_UP* pRing, const char* pBuffer, } NumBytesToWrite = MIN(NumBytesToWrite, (pRing->SizeOfBuffer - WrOff)); // Number of bytes that can be written until buffer wrap-around NumBytesToWrite = MIN(NumBytesToWrite, NumBytes); + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; #if SEGGER_RTT_MEMCPY_USE_BYTELOOP - pDst = pRing->pBuffer + WrOff; NumBytesWritten += NumBytesToWrite; NumBytes -= NumBytesToWrite; WrOff += NumBytesToWrite; @@ -353,7 +401,7 @@ static unsigned _WriteBlocking(SEGGER_RTT_BUFFER_UP* pRing, const char* pBuffer, *pDst++ = *pBuffer++; }; #else - SEGGER_RTT_MEMCPY(pRing->pBuffer + WrOff, pBuffer, NumBytesToWrite); + SEGGER_RTT_MEMCPY((void*)pDst, pBuffer, NumBytesToWrite); NumBytesWritten += NumBytesToWrite; pBuffer += NumBytesToWrite; NumBytes -= NumBytesToWrite; @@ -362,9 +410,9 @@ static unsigned _WriteBlocking(SEGGER_RTT_BUFFER_UP* pRing, const char* pBuffer, if (WrOff == pRing->SizeOfBuffer) { WrOff = 0u; } + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses pRing->WrOff = WrOff; } while (NumBytes); - // return NumBytesWritten; } @@ -390,9 +438,7 @@ static void _WriteNoCheck(SEGGER_RTT_BUFFER_UP* pRing, const char* pData, unsign unsigned NumBytesAtOnce; unsigned WrOff; unsigned Rem; -#if SEGGER_RTT_MEMCPY_USE_BYTELOOP - char* pDst; -#endif + volatile char* pDst; WrOff = pRing->WrOff; Rem = pRing->SizeOfBuffer - WrOff; @@ -400,15 +446,17 @@ static void _WriteNoCheck(SEGGER_RTT_BUFFER_UP* pRing, const char* pData, unsign // // All data fits before wrap around // + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; #if SEGGER_RTT_MEMCPY_USE_BYTELOOP - pDst = pRing->pBuffer + WrOff; WrOff += NumBytes; while (NumBytes--) { *pDst++ = *pData++; }; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses pRing->WrOff = WrOff; #else - SEGGER_RTT_MEMCPY(pRing->pBuffer + WrOff, pData, NumBytes); + SEGGER_RTT_MEMCPY((void*)pDst, pData, NumBytes); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses pRing->WrOff = WrOff + NumBytes; #endif } else { @@ -416,22 +464,26 @@ static void _WriteNoCheck(SEGGER_RTT_BUFFER_UP* pRing, const char* pData, unsign // We reach the end of the buffer, so need to wrap around // #if SEGGER_RTT_MEMCPY_USE_BYTELOOP - pDst = pRing->pBuffer + WrOff; + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; NumBytesAtOnce = Rem; while (NumBytesAtOnce--) { *pDst++ = *pData++; }; - pDst = pRing->pBuffer; + pDst = pRing->pBuffer + SEGGER_RTT_UNCACHED_OFF; NumBytesAtOnce = NumBytes - Rem; while (NumBytesAtOnce--) { *pDst++ = *pData++; }; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses pRing->WrOff = NumBytes - Rem; #else NumBytesAtOnce = Rem; - SEGGER_RTT_MEMCPY(pRing->pBuffer + WrOff, pData, NumBytesAtOnce); + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; + SEGGER_RTT_MEMCPY((void*)pDst, pData, NumBytesAtOnce); NumBytesAtOnce = NumBytes - Rem; - SEGGER_RTT_MEMCPY(pRing->pBuffer, pData + Rem, NumBytesAtOnce); + pDst = pRing->pBuffer + SEGGER_RTT_UNCACHED_OFF; + SEGGER_RTT_MEMCPY((void*)pDst, pData + Rem, NumBytesAtOnce); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses pRing->WrOff = NumBytesAtOnce; #endif } @@ -496,6 +548,7 @@ static unsigned _GetAvailWriteSpace(SEGGER_RTT_BUFFER_UP* pRing) { * ********************************************************************** */ + /********************************************************************* * * SEGGER_RTT_ReadUpBufferNoLock() @@ -525,12 +578,10 @@ unsigned SEGGER_RTT_ReadUpBufferNoLock(unsigned BufferIndex, void* pData, unsign unsigned WrOff; unsigned char* pBuffer; SEGGER_RTT_BUFFER_UP* pRing; -#if SEGGER_RTT_MEMCPY_USE_BYTELOOP - const char* pSrc; -#endif - // + volatile char* pSrc; + INIT(); - pRing = &_SEGGER_RTT.aUp[BufferIndex]; + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly pBuffer = (unsigned char*)pData; RdOff = pRing->RdOff; WrOff = pRing->WrOff; @@ -541,8 +592,8 @@ unsigned SEGGER_RTT_ReadUpBufferNoLock(unsigned BufferIndex, void* pData, unsign if (RdOff > WrOff) { NumBytesRem = pRing->SizeOfBuffer - RdOff; NumBytesRem = MIN(NumBytesRem, BufferSize); + pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF; #if SEGGER_RTT_MEMCPY_USE_BYTELOOP - pSrc = pRing->pBuffer + RdOff; NumBytesRead += NumBytesRem; BufferSize -= NumBytesRem; RdOff += NumBytesRem; @@ -550,7 +601,7 @@ unsigned SEGGER_RTT_ReadUpBufferNoLock(unsigned BufferIndex, void* pData, unsign *pBuffer++ = *pSrc++; }; #else - SEGGER_RTT_MEMCPY(pBuffer, pRing->pBuffer + RdOff, NumBytesRem); + SEGGER_RTT_MEMCPY(pBuffer, (void*)pSrc, NumBytesRem); NumBytesRead += NumBytesRem; pBuffer += NumBytesRem; BufferSize -= NumBytesRem; @@ -569,8 +620,8 @@ unsigned SEGGER_RTT_ReadUpBufferNoLock(unsigned BufferIndex, void* pData, unsign NumBytesRem = WrOff - RdOff; NumBytesRem = MIN(NumBytesRem, BufferSize); if (NumBytesRem > 0u) { + pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF; #if SEGGER_RTT_MEMCPY_USE_BYTELOOP - pSrc = pRing->pBuffer + RdOff; NumBytesRead += NumBytesRem; BufferSize -= NumBytesRem; RdOff += NumBytesRem; @@ -578,7 +629,7 @@ unsigned SEGGER_RTT_ReadUpBufferNoLock(unsigned BufferIndex, void* pData, unsign *pBuffer++ = *pSrc++; }; #else - SEGGER_RTT_MEMCPY(pBuffer, pRing->pBuffer + RdOff, NumBytesRem); + SEGGER_RTT_MEMCPY(pBuffer, (void*)pSrc, NumBytesRem); NumBytesRead += NumBytesRem; pBuffer += NumBytesRem; BufferSize -= NumBytesRem; @@ -619,12 +670,10 @@ unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned Buffe unsigned WrOff; unsigned char* pBuffer; SEGGER_RTT_BUFFER_DOWN* pRing; -#if SEGGER_RTT_MEMCPY_USE_BYTELOOP - const char* pSrc; -#endif + volatile char* pSrc; // INIT(); - pRing = &_SEGGER_RTT.aDown[BufferIndex]; + pRing = (SEGGER_RTT_BUFFER_DOWN*)((char*)&_SEGGER_RTT.aDown[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly pBuffer = (unsigned char*)pData; RdOff = pRing->RdOff; WrOff = pRing->WrOff; @@ -635,8 +684,8 @@ unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned Buffe if (RdOff > WrOff) { NumBytesRem = pRing->SizeOfBuffer - RdOff; NumBytesRem = MIN(NumBytesRem, BufferSize); + pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF; #if SEGGER_RTT_MEMCPY_USE_BYTELOOP - pSrc = pRing->pBuffer + RdOff; NumBytesRead += NumBytesRem; BufferSize -= NumBytesRem; RdOff += NumBytesRem; @@ -644,7 +693,7 @@ unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned Buffe *pBuffer++ = *pSrc++; }; #else - SEGGER_RTT_MEMCPY(pBuffer, pRing->pBuffer + RdOff, NumBytesRem); + SEGGER_RTT_MEMCPY(pBuffer, (void*)pSrc, NumBytesRem); NumBytesRead += NumBytesRem; pBuffer += NumBytesRem; BufferSize -= NumBytesRem; @@ -663,8 +712,8 @@ unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned Buffe NumBytesRem = WrOff - RdOff; NumBytesRem = MIN(NumBytesRem, BufferSize); if (NumBytesRem > 0u) { + pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF; #if SEGGER_RTT_MEMCPY_USE_BYTELOOP - pSrc = pRing->pBuffer + RdOff; NumBytesRead += NumBytesRem; BufferSize -= NumBytesRem; RdOff += NumBytesRem; @@ -672,7 +721,7 @@ unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned Buffe *pBuffer++ = *pSrc++; }; #else - SEGGER_RTT_MEMCPY(pBuffer, pRing->pBuffer + RdOff, NumBytesRem); + SEGGER_RTT_MEMCPY(pBuffer, (void*)pSrc, NumBytesRem); NumBytesRead += NumBytesRem; pBuffer += NumBytesRem; BufferSize -= NumBytesRem; @@ -713,7 +762,7 @@ unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned Buffe */ unsigned SEGGER_RTT_ReadUpBuffer(unsigned BufferIndex, void* pBuffer, unsigned BufferSize) { unsigned NumBytesRead; - // + SEGGER_RTT_LOCK(); // // Call the non-locking read function @@ -745,7 +794,7 @@ unsigned SEGGER_RTT_ReadUpBuffer(unsigned BufferIndex, void* pBuffer, unsigned B */ unsigned SEGGER_RTT_Read(unsigned BufferIndex, void* pBuffer, unsigned BufferSize) { unsigned NumBytesRead; - // + SEGGER_RTT_LOCK(); // // Call the non-locking read function @@ -786,15 +835,12 @@ void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuff const char* pData; SEGGER_RTT_BUFFER_UP* pRing; unsigned Avail; -#if SEGGER_RTT_MEMCPY_USE_BYTELOOP - char* pDst; -#endif - - pData = (const char *)pBuffer; + volatile char* pDst; // // Get "to-host" ring buffer and copy some elements into local variables. // - pRing = &_SEGGER_RTT.aUp[BufferIndex]; + pData = (const char *)pBuffer; + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly // // Check if we will overwrite data and need to adjust the RdOff. // @@ -820,15 +866,17 @@ void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuff // // Last round // + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; #if SEGGER_RTT_MEMCPY_USE_BYTELOOP - pDst = pRing->pBuffer + pRing->WrOff; Avail = NumBytes; while (NumBytes--) { *pDst++ = *pData++; }; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses pRing->WrOff += Avail; #else - SEGGER_RTT_MEMCPY(pRing->pBuffer + pRing->WrOff, pData, NumBytes); + SEGGER_RTT_MEMCPY((void*)pDst, pData, NumBytes); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses pRing->WrOff += NumBytes; #endif break; @@ -836,16 +884,18 @@ void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuff // // Wrap-around necessary, write until wrap-around and reset WrOff // + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; #if SEGGER_RTT_MEMCPY_USE_BYTELOOP - pDst = pRing->pBuffer + pRing->WrOff; NumBytes -= Avail; while (Avail--) { *pDst++ = *pData++; }; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses pRing->WrOff = 0; #else - SEGGER_RTT_MEMCPY(pRing->pBuffer + pRing->WrOff, pData, Avail); + SEGGER_RTT_MEMCPY((void*)pDst, pData, Avail); pData += Avail; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses pRing->WrOff = 0; NumBytes -= Avail; #endif @@ -889,6 +939,7 @@ unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pBuffer, u unsigned RdOff; unsigned WrOff; unsigned Rem; + volatile char* pDst; // // Cases: // 1) RdOff <= WrOff => Space until wrap-around is sufficient @@ -900,21 +951,22 @@ unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pBuffer, u // 1) is the most common case for large buffers and assuming that J-Link reads the data fast enough // pData = (const char *)pBuffer; - pRing = &_SEGGER_RTT.aUp[BufferIndex]; + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly RdOff = pRing->RdOff; WrOff = pRing->WrOff; + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; if (RdOff <= WrOff) { // Case 1), 2) or 3) Avail = pRing->SizeOfBuffer - WrOff - 1u; // Space until wrap-around (assume 1 byte not usable for case that RdOff == 0) if (Avail >= NumBytes) { // Case 1)? -CopyStraight: - memcpy(pRing->pBuffer + WrOff, pData, NumBytes); + memcpy((void*)pDst, pData, NumBytes); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses pRing->WrOff = WrOff + NumBytes; return 1; } Avail += RdOff; // Space incl. wrap-around if (Avail >= NumBytes) { // Case 2? => If not, we have case 3) (does not fit) Rem = pRing->SizeOfBuffer - WrOff; // Space until end of buffer - memcpy(pRing->pBuffer + WrOff, pData, Rem); // Copy 1st chunk + memcpy((void*)pDst, pData, Rem); // Copy 1st chunk NumBytes -= Rem; // // Special case: First check that assumed RdOff == 0 calculated that last element before wrap-around could not be used @@ -923,15 +975,20 @@ CopyStraight: // Therefore, check if 2nd memcpy is necessary at all // if (NumBytes) { - memcpy(pRing->pBuffer, pData + Rem, NumBytes); + pDst = pRing->pBuffer + SEGGER_RTT_UNCACHED_OFF; + memcpy((void*)pDst, pData + Rem, NumBytes); } + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses pRing->WrOff = NumBytes; return 1; } } else { // Potential case 4) Avail = RdOff - WrOff - 1u; if (Avail >= NumBytes) { // Case 4)? => If not, we have case 5) (does not fit) - goto CopyStraight; + memcpy((void*)pDst, pData, NumBytes); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses + pRing->WrOff = WrOff + NumBytes; + return 1; } } return 0; // No space in buffer @@ -971,13 +1028,12 @@ unsigned SEGGER_RTT_WriteDownBufferNoLock(unsigned BufferIndex, const void* pBuf unsigned Avail; const char* pData; SEGGER_RTT_BUFFER_UP* pRing; - - pData = (const char *)pBuffer; // // Get "to-target" ring buffer. // It is save to cast that to a "to-host" buffer. Up and Down buffer differ in volatility of offsets that might be modified by J-Link. // - pRing = (SEGGER_RTT_BUFFER_UP*)&_SEGGER_RTT.aDown[BufferIndex]; + pData = (const char *)pBuffer; + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aDown[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly // // How we output depends upon the mode... // @@ -1047,12 +1103,11 @@ unsigned SEGGER_RTT_WriteNoLock(unsigned BufferIndex, const void* pBuffer, unsig unsigned Avail; const char* pData; SEGGER_RTT_BUFFER_UP* pRing; - - pData = (const char *)pBuffer; // // Get "to-host" ring buffer. // - pRing = &_SEGGER_RTT.aUp[BufferIndex]; + pData = (const char *)pBuffer; + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly // // How we output depends upon the mode... // @@ -1121,18 +1176,11 @@ unsigned SEGGER_RTT_WriteNoLock(unsigned BufferIndex, const void* pBuffer, unsig */ unsigned SEGGER_RTT_WriteDownBuffer(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { unsigned Status; - // + INIT(); SEGGER_RTT_LOCK(); - // - // Call the non-locking write function - // - Status = SEGGER_RTT_WriteDownBufferNoLock(BufferIndex, pBuffer, NumBytes); - // - // Finish up. - // + Status = SEGGER_RTT_WriteDownBufferNoLock(BufferIndex, pBuffer, NumBytes); // Call the non-locking write function SEGGER_RTT_UNLOCK(); - // return Status; } @@ -1157,18 +1205,11 @@ unsigned SEGGER_RTT_WriteDownBuffer(unsigned BufferIndex, const void* pBuffer, u */ unsigned SEGGER_RTT_Write(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { unsigned Status; - // + INIT(); SEGGER_RTT_LOCK(); - // - // Call the non-locking write function - // - Status = SEGGER_RTT_WriteNoLock(BufferIndex, pBuffer, NumBytes); - // - // Finish up. - // + Status = SEGGER_RTT_WriteNoLock(BufferIndex, pBuffer, NumBytes); // Call the non-locking write function SEGGER_RTT_UNLOCK(); - // return Status; } @@ -1226,10 +1267,11 @@ unsigned SEGGER_RTT_PutCharSkipNoLock(unsigned BufferIndex, char c) { SEGGER_RTT_BUFFER_UP* pRing; unsigned WrOff; unsigned Status; + volatile char* pDst; // // Get "to-host" ring buffer. // - pRing = &_SEGGER_RTT.aUp[BufferIndex]; + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly // // Get write position and handle wrap-around if necessary // @@ -1241,7 +1283,9 @@ unsigned SEGGER_RTT_PutCharSkipNoLock(unsigned BufferIndex, char c) { // Output byte if free space is available // if (WrOff != pRing->RdOff) { - pRing->pBuffer[pRing->WrOff] = c; + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; + *pDst = c; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses pRing->WrOff = WrOff; Status = 1; } else { @@ -1273,6 +1317,7 @@ unsigned SEGGER_RTT_PutCharSkip(unsigned BufferIndex, char c) { SEGGER_RTT_BUFFER_UP* pRing; unsigned WrOff; unsigned Status; + volatile char* pDst; // // Prepare // @@ -1281,7 +1326,7 @@ unsigned SEGGER_RTT_PutCharSkip(unsigned BufferIndex, char c) { // // Get "to-host" ring buffer. // - pRing = &_SEGGER_RTT.aUp[BufferIndex]; + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly // // Get write position and handle wrap-around if necessary // @@ -1293,7 +1338,9 @@ unsigned SEGGER_RTT_PutCharSkip(unsigned BufferIndex, char c) { // Output byte if free space is available // if (WrOff != pRing->RdOff) { - pRing->pBuffer[pRing->WrOff] = c; + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; + *pDst = c; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses pRing->WrOff = WrOff; Status = 1; } else { @@ -1329,6 +1376,7 @@ unsigned SEGGER_RTT_PutChar(unsigned BufferIndex, char c) { SEGGER_RTT_BUFFER_UP* pRing; unsigned WrOff; unsigned Status; + volatile char* pDst; // // Prepare // @@ -1337,7 +1385,7 @@ unsigned SEGGER_RTT_PutChar(unsigned BufferIndex, char c) { // // Get "to-host" ring buffer. // - pRing = &_SEGGER_RTT.aUp[BufferIndex]; + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly // // Get write position and handle wrap-around if necessary // @@ -1357,7 +1405,9 @@ unsigned SEGGER_RTT_PutChar(unsigned BufferIndex, char c) { // Output byte if free space is available // if (WrOff != pRing->RdOff) { - pRing->pBuffer[pRing->WrOff] = c; + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; + *pDst = c; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses pRing->WrOff = WrOff; Status = 1; } else { @@ -1367,7 +1417,6 @@ unsigned SEGGER_RTT_PutChar(unsigned BufferIndex, char c) { // Finish up. // SEGGER_RTT_UNLOCK(); - // return Status; } @@ -1404,7 +1453,7 @@ int SEGGER_RTT_GetKey(void) { * SEGGER_RTT_WaitKey * * Function description -* Waits until at least one character is available in the SEGGER RTT buffer. +* Waits until at least one character is avaible in the SEGGER RTT buffer. * Once a character is available, it is read and this function returns. * * Return value @@ -1438,12 +1487,14 @@ int SEGGER_RTT_WaitKey(void) { * (1) This function is only specified for accesses to RTT buffer 0 */ int SEGGER_RTT_HasKey(void) { + SEGGER_RTT_BUFFER_DOWN* pRing; unsigned RdOff; int r; INIT(); - RdOff = _SEGGER_RTT.aDown[0].RdOff; - if (RdOff != _SEGGER_RTT.aDown[0].WrOff) { + pRing = (SEGGER_RTT_BUFFER_DOWN*)((char*)&_SEGGER_RTT.aDown[0] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + RdOff = pRing->RdOff; + if (RdOff != pRing->WrOff) { r = 1; } else { r = 0; @@ -1467,7 +1518,7 @@ unsigned SEGGER_RTT_HasData(unsigned BufferIndex) { SEGGER_RTT_BUFFER_DOWN* pRing; unsigned v; - pRing = &_SEGGER_RTT.aDown[BufferIndex]; + pRing = (SEGGER_RTT_BUFFER_DOWN*)((char*)&_SEGGER_RTT.aDown[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly v = pRing->WrOff; return v - pRing->RdOff; } @@ -1488,7 +1539,7 @@ unsigned SEGGER_RTT_HasDataUp(unsigned BufferIndex) { SEGGER_RTT_BUFFER_UP* pRing; unsigned v; - pRing = &_SEGGER_RTT.aUp[BufferIndex]; + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly v = pRing->RdOff; return pRing->WrOff - v; } @@ -1507,6 +1558,7 @@ unsigned SEGGER_RTT_HasDataUp(unsigned BufferIndex) { * pBuffer Pointer to a buffer to be used. * BufferSize Size of the buffer. * Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. * * Return value * >= 0 - O.K. Buffer Index @@ -1514,23 +1566,26 @@ unsigned SEGGER_RTT_HasDataUp(unsigned BufferIndex) { */ int SEGGER_RTT_AllocDownBuffer(const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { int BufferIndex; + volatile SEGGER_RTT_CB* pRTTCB; INIT(); SEGGER_RTT_LOCK(); + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly BufferIndex = 0; do { - if (_SEGGER_RTT.aDown[BufferIndex].pBuffer == NULL) { + if (pRTTCB->aDown[BufferIndex].pBuffer == NULL) { break; } BufferIndex++; - } while (BufferIndex < _SEGGER_RTT.MaxNumDownBuffers); - if (BufferIndex < _SEGGER_RTT.MaxNumDownBuffers) { - _SEGGER_RTT.aDown[BufferIndex].sName = sName; - _SEGGER_RTT.aDown[BufferIndex].pBuffer = (char*)pBuffer; - _SEGGER_RTT.aDown[BufferIndex].SizeOfBuffer = BufferSize; - _SEGGER_RTT.aDown[BufferIndex].RdOff = 0u; - _SEGGER_RTT.aDown[BufferIndex].WrOff = 0u; - _SEGGER_RTT.aDown[BufferIndex].Flags = Flags; + } while (BufferIndex < pRTTCB->MaxNumDownBuffers); + if (BufferIndex < pRTTCB->MaxNumDownBuffers) { + pRTTCB->aDown[BufferIndex].sName = sName; + pRTTCB->aDown[BufferIndex].pBuffer = (char*)pBuffer; + pRTTCB->aDown[BufferIndex].SizeOfBuffer = BufferSize; + pRTTCB->aDown[BufferIndex].RdOff = 0u; + pRTTCB->aDown[BufferIndex].WrOff = 0u; + pRTTCB->aDown[BufferIndex].Flags = Flags; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses } else { BufferIndex = -1; } @@ -1552,6 +1607,7 @@ int SEGGER_RTT_AllocDownBuffer(const char* sName, void* pBuffer, unsigned Buffer * pBuffer Pointer to a buffer to be used. * BufferSize Size of the buffer. * Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. * * Return value * >= 0 - O.K. Buffer Index @@ -1559,23 +1615,26 @@ int SEGGER_RTT_AllocDownBuffer(const char* sName, void* pBuffer, unsigned Buffer */ int SEGGER_RTT_AllocUpBuffer(const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { int BufferIndex; + volatile SEGGER_RTT_CB* pRTTCB; INIT(); SEGGER_RTT_LOCK(); + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly BufferIndex = 0; do { - if (_SEGGER_RTT.aUp[BufferIndex].pBuffer == NULL) { + if (pRTTCB->aUp[BufferIndex].pBuffer == NULL) { break; } BufferIndex++; - } while (BufferIndex < _SEGGER_RTT.MaxNumUpBuffers); - if (BufferIndex < _SEGGER_RTT.MaxNumUpBuffers) { - _SEGGER_RTT.aUp[BufferIndex].sName = sName; - _SEGGER_RTT.aUp[BufferIndex].pBuffer = (char*)pBuffer; - _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer = BufferSize; - _SEGGER_RTT.aUp[BufferIndex].RdOff = 0u; - _SEGGER_RTT.aUp[BufferIndex].WrOff = 0u; - _SEGGER_RTT.aUp[BufferIndex].Flags = Flags; + } while (BufferIndex < pRTTCB->MaxNumUpBuffers); + if (BufferIndex < pRTTCB->MaxNumUpBuffers) { + pRTTCB->aUp[BufferIndex].sName = sName; + pRTTCB->aUp[BufferIndex].pBuffer = (char*)pBuffer; + pRTTCB->aUp[BufferIndex].SizeOfBuffer = BufferSize; + pRTTCB->aUp[BufferIndex].RdOff = 0u; + pRTTCB->aUp[BufferIndex].WrOff = 0u; + pRTTCB->aUp[BufferIndex].Flags = Flags; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses } else { BufferIndex = -1; } @@ -1598,6 +1657,7 @@ int SEGGER_RTT_AllocUpBuffer(const char* sName, void* pBuffer, unsigned BufferSi * pBuffer Pointer to a buffer to be used. * BufferSize Size of the buffer. * Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. * * Return value * >= 0 - O.K. @@ -1610,18 +1670,22 @@ int SEGGER_RTT_AllocUpBuffer(const char* sName, void* pBuffer, unsigned BufferSi */ int SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_UP* pUp; INIT(); - if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumUpBuffers) { + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_UP_BUFFERS) { SEGGER_RTT_LOCK(); - if (BufferIndex > 0u) { - _SEGGER_RTT.aUp[BufferIndex].sName = sName; - _SEGGER_RTT.aUp[BufferIndex].pBuffer = (char*)pBuffer; - _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer = BufferSize; - _SEGGER_RTT.aUp[BufferIndex].RdOff = 0u; - _SEGGER_RTT.aUp[BufferIndex].WrOff = 0u; + pUp = &pRTTCB->aUp[BufferIndex]; + if (BufferIndex) { + pUp->sName = sName; + pUp->pBuffer = (char*)pBuffer; + pUp->SizeOfBuffer = BufferSize; + pUp->RdOff = 0u; + pUp->WrOff = 0u; } - _SEGGER_RTT.aUp[BufferIndex].Flags = Flags; + pUp->Flags = Flags; SEGGER_RTT_UNLOCK(); r = 0; } else { @@ -1645,6 +1709,7 @@ int SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex, const char* sName, void* pBu * pBuffer Pointer to a buffer to be used. * BufferSize Size of the buffer. * Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. * * Return value * >= 0 O.K. @@ -1657,18 +1722,23 @@ int SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex, const char* sName, void* pBu */ int SEGGER_RTT_ConfigDownBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_DOWN* pDown; INIT(); - if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumDownBuffers) { + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_DOWN_BUFFERS) { SEGGER_RTT_LOCK(); - if (BufferIndex > 0u) { - _SEGGER_RTT.aDown[BufferIndex].sName = sName; - _SEGGER_RTT.aDown[BufferIndex].pBuffer = (char*)pBuffer; - _SEGGER_RTT.aDown[BufferIndex].SizeOfBuffer = BufferSize; - _SEGGER_RTT.aDown[BufferIndex].RdOff = 0u; - _SEGGER_RTT.aDown[BufferIndex].WrOff = 0u; + pDown = &pRTTCB->aDown[BufferIndex]; + if (BufferIndex) { + pDown->sName = sName; + pDown->pBuffer = (char*)pBuffer; + pDown->SizeOfBuffer = BufferSize; + pDown->RdOff = 0u; + pDown->WrOff = 0u; } - _SEGGER_RTT.aDown[BufferIndex].Flags = Flags; + pDown->Flags = Flags; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is allowed to change the order of memory accesses SEGGER_RTT_UNLOCK(); r = 0; } else { @@ -1695,11 +1765,15 @@ int SEGGER_RTT_ConfigDownBuffer(unsigned BufferIndex, const char* sName, void* p */ int SEGGER_RTT_SetNameUpBuffer(unsigned BufferIndex, const char* sName) { int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_UP* pUp; INIT(); - if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumUpBuffers) { + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_UP_BUFFERS) { SEGGER_RTT_LOCK(); - _SEGGER_RTT.aUp[BufferIndex].sName = sName; + pUp = &pRTTCB->aUp[BufferIndex]; + pUp->sName = sName; SEGGER_RTT_UNLOCK(); r = 0; } else { @@ -1726,11 +1800,15 @@ int SEGGER_RTT_SetNameUpBuffer(unsigned BufferIndex, const char* sName) { */ int SEGGER_RTT_SetNameDownBuffer(unsigned BufferIndex, const char* sName) { int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_DOWN* pDown; INIT(); - if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumDownBuffers) { + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_DOWN_BUFFERS) { SEGGER_RTT_LOCK(); - _SEGGER_RTT.aDown[BufferIndex].sName = sName; + pDown = &pRTTCB->aDown[BufferIndex]; + pDown->sName = sName; SEGGER_RTT_UNLOCK(); r = 0; } else { @@ -1750,6 +1828,7 @@ int SEGGER_RTT_SetNameDownBuffer(unsigned BufferIndex, const char* sName) { * Parameters * BufferIndex Index of the buffer. * Flags Flags to set for the buffer. +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. * * Return value * >= 0 O.K. @@ -1757,11 +1836,15 @@ int SEGGER_RTT_SetNameDownBuffer(unsigned BufferIndex, const char* sName) { */ int SEGGER_RTT_SetFlagsUpBuffer(unsigned BufferIndex, unsigned Flags) { int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_UP* pUp; INIT(); - if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumUpBuffers) { + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_UP_BUFFERS) { SEGGER_RTT_LOCK(); - _SEGGER_RTT.aUp[BufferIndex].Flags = Flags; + pUp = &pRTTCB->aUp[BufferIndex]; + pUp->Flags = Flags; SEGGER_RTT_UNLOCK(); r = 0; } else { @@ -1781,6 +1864,7 @@ int SEGGER_RTT_SetFlagsUpBuffer(unsigned BufferIndex, unsigned Flags) { * Parameters * BufferIndex Index of the buffer to renamed. * Flags Flags to set for the buffer. +* Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. * * Return value * >= 0 O.K. @@ -1788,11 +1872,15 @@ int SEGGER_RTT_SetFlagsUpBuffer(unsigned BufferIndex, unsigned Flags) { */ int SEGGER_RTT_SetFlagsDownBuffer(unsigned BufferIndex, unsigned Flags) { int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_DOWN* pDown; INIT(); - if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumDownBuffers) { + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_DOWN_BUFFERS) { SEGGER_RTT_LOCK(); - _SEGGER_RTT.aDown[BufferIndex].Flags = Flags; + pDown = &pRTTCB->aDown[BufferIndex]; + pDown->Flags = Flags; SEGGER_RTT_UNLOCK(); r = 0; } else { @@ -1827,21 +1915,23 @@ void SEGGER_RTT_Init (void) { * Return value * >= 0 O.K. * < 0 Error (e.g. if RTT is configured for non-blocking mode and there was no space in the buffer to set the new terminal Id) +* +* Notes +* (1) Buffer 0 is always reserved for terminal I/O, so we can use index 0 here, fixed */ int SEGGER_RTT_SetTerminal (unsigned char TerminalId) { unsigned char ac[2]; SEGGER_RTT_BUFFER_UP* pRing; unsigned Avail; int r; - // + INIT(); - // r = 0; ac[0] = 0xFFu; if (TerminalId < sizeof(_aTerminalId)) { // We only support a certain number of channels ac[1] = _aTerminalId[TerminalId]; - pRing = &_SEGGER_RTT.aUp[0]; // Buffer 0 is always reserved for terminal I/O, so we can use index 0 here, fixed - SEGGER_RTT_LOCK(); // Lock to make sure that no other task is writing into buffer, while we are and number of free bytes in buffer does not change downwards after checking and before writing + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[0] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + SEGGER_RTT_LOCK(); // Lock to make sure that no other task is writing into buffer, while we are and number of free bytes in buffer does not change downwards after checking and before writing if ((pRing->Flags & SEGGER_RTT_MODE_MASK) == SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL) { _ActiveTerminal = TerminalId; _WriteBlocking(pRing, (const char*)ac, 2u); @@ -1892,7 +1982,7 @@ int SEGGER_RTT_TerminalOut (unsigned char TerminalId, const char* s) { // // Get "to-host" ring buffer. // - pRing = &_SEGGER_RTT.aUp[0]; + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[0] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly // // Need to be able to change terminal, write data, change back. // Compute the fixed and variable sizes. @@ -1966,8 +2056,11 @@ int SEGGER_RTT_TerminalOut (unsigned char TerminalId, const char* s) { * Return value * Number of bytes that are free in the selected up buffer. */ -unsigned SEGGER_RTT_GetAvailWriteSpace (unsigned BufferIndex){ - return _GetAvailWriteSpace(&_SEGGER_RTT.aUp[BufferIndex]); +unsigned SEGGER_RTT_GetAvailWriteSpace (unsigned BufferIndex) { + SEGGER_RTT_BUFFER_UP* pRing; + + pRing = (SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[BufferIndex] + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + return _GetAvailWriteSpace(pRing); } @@ -1988,16 +2081,18 @@ unsigned SEGGER_RTT_GetBytesInBuffer(unsigned BufferIndex) { unsigned RdOff; unsigned WrOff; unsigned r; + volatile SEGGER_RTT_CB* pRTTCB; // // Avoid warnings regarding volatile access order. It's not a problem // in this case, but dampen compiler enthusiasm. // - RdOff = _SEGGER_RTT.aUp[BufferIndex].RdOff; - WrOff = _SEGGER_RTT.aUp[BufferIndex].WrOff; + pRTTCB = (volatile SEGGER_RTT_CB*)((unsigned char*)&_SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly + RdOff = pRTTCB->aUp[BufferIndex].RdOff; + WrOff = pRTTCB->aUp[BufferIndex].WrOff; if (RdOff <= WrOff) { r = WrOff - RdOff; } else { - r = _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer - (WrOff - RdOff); + r = pRTTCB->aUp[BufferIndex].SizeOfBuffer - (WrOff - RdOff); } return r; } diff --git a/lib/SEGGER_RTT/RTT/SEGGER_RTT.h b/lib/SEGGER_RTT/RTT/SEGGER_RTT.h index 07eb4f39e..a3161f694 100644 --- a/lib/SEGGER_RTT/RTT/SEGGER_RTT.h +++ b/lib/SEGGER_RTT/RTT/SEGGER_RTT.h @@ -46,16 +46,14 @@ File : SEGGER_RTT.h Purpose : Implementation of SEGGER real-time transfer which allows real-time communication on targets which support debugger memory accesses while the CPU is running. -Revision: $Rev: 17697 $ +Revision: $Rev: 25842 $ ---------------------------------------------------------------------- */ #ifndef SEGGER_RTT_H #define SEGGER_RTT_H -#include "SEGGER_RTT_Conf.h" - - +#include "../Config/SEGGER_RTT_Conf.h" /********************************************************************* * @@ -63,46 +61,168 @@ Revision: $Rev: 17697 $ * ********************************************************************** */ + #ifndef RTT_USE_ASM - #if (defined __SES_ARM) // SEGGER Embedded Studio + // + // Some cores support out-of-order memory accesses (reordering of memory accesses in the core) + // For such cores, we need to define a memory barrier to guarantee the order of certain accesses to the RTT ring buffers. + // Needed for: + // Cortex-M7 (ARMv7-M) + // Cortex-M23 (ARM-v8M) + // Cortex-M33 (ARM-v8M) + // Cortex-A/R (ARM-v7A/R) + // + // We do not explicitly check for "Embedded Studio" as the compiler in use determines what we support. + // You can use an external toolchain like IAR inside ES. So there is no point in checking for "Embedded Studio" + // + #if (defined __CROSSWORKS_ARM) // Rowley Crossworks #define _CC_HAS_RTT_ASM_SUPPORT 1 - #elif (defined __CROSSWORKS_ARM) // Rowley Crossworks - #define _CC_HAS_RTT_ASM_SUPPORT 1 - #elif (defined __GNUC__) // GCC - #define _CC_HAS_RTT_ASM_SUPPORT 1 - #elif (defined __clang__) // Clang compiler - #define _CC_HAS_RTT_ASM_SUPPORT 1 - #elif (defined __IASMARM__) // IAR assembler - #define _CC_HAS_RTT_ASM_SUPPORT 1 - #elif (defined __ICCARM__) // IAR compiler - #define _CC_HAS_RTT_ASM_SUPPORT 1 - #else - #define _CC_HAS_RTT_ASM_SUPPORT 0 - #endif - #if (defined __ARM_ARCH_7M__) // Cortex-M3/4 - #define _CORE_HAS_RTT_ASM_SUPPORT 1 - #elif (defined __ARM_ARCH_7EM__) // Cortex-M7 - #define _CORE_HAS_RTT_ASM_SUPPORT 1 - #elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33 - #define _CORE_HAS_RTT_ASM_SUPPORT 1 - #elif (defined __ARM7M__) // IAR Cortex-M3/4 - #if (__CORE__ == __ARM7M__) + #if (defined __ARM_ARCH_7M__) // Cortex-M3 #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23 + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); #else #define _CORE_HAS_RTT_ASM_SUPPORT 0 #endif - #elif (defined __ARM7EM__) // IAR Cortex-M7 - #if (__CORE__ == __ARM7EM__) + #elif (defined __ARMCC_VERSION) + // + // ARM compiler + // ARM compiler V6.0 and later is clang based. + // Our ASM part is compatible to clang. + // + #if (__ARMCC_VERSION >= 6000000) + #define _CC_HAS_RTT_ASM_SUPPORT 1 + #else + #define _CC_HAS_RTT_ASM_SUPPORT 0 + #endif + #if (defined __ARM_ARCH_6M__) // Cortex-M0 / M1 + #define _CORE_HAS_RTT_ASM_SUPPORT 0 // No ASM support for this architecture + #elif (defined __ARM_ARCH_7M__) // Cortex-M3 #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23 + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif ((defined __ARM_ARCH_7A__) || (defined __ARM_ARCH_7R__)) // Cortex-A/R 32-bit ARMv7-A/R + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); #else #define _CORE_HAS_RTT_ASM_SUPPORT 0 #endif + #elif ((defined __GNUC__) || (defined __clang__)) + // + // GCC / Clang + // + #define _CC_HAS_RTT_ASM_SUPPORT 1 + // ARM 7/9: __ARM_ARCH_5__ / __ARM_ARCH_5E__ / __ARM_ARCH_5T__ / __ARM_ARCH_5T__ / __ARM_ARCH_5TE__ + #if (defined __ARM_ARCH_7M__) // Cortex-M3 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 // Only Cortex-M7 needs a DMB but we cannot distinguish M4 and M7 here... + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23 + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #elif ((defined __ARM_ARCH_7A__) || (defined __ARM_ARCH_7R__)) // Cortex-A/R 32-bit ARMv7-A/R + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() __asm volatile ("dmb\n" : : :); + #else + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #endif + #elif ((defined __IASMARM__) || (defined __ICCARM__)) + // + // IAR assembler/compiler + // + #define _CC_HAS_RTT_ASM_SUPPORT 1 + #if (__VER__ < 6300000) + #define VOLATILE + #else + #define VOLATILE volatile + #endif + #if (defined __ARM7M__) // Needed for old versions that do not know the define yet + #if (__CORE__ == __ARM7M__) // Cortex-M3 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #endif + #endif + #if (defined __ARM7EM__) + #if (__CORE__ == __ARM7EM__) // Cortex-M4/M7 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() asm VOLATILE ("DMB"); + #endif + #endif + #if (defined __ARM8M_BASELINE__) + #if (__CORE__ == __ARM8M_BASELINE__) // Cortex-M23 + #define _CORE_HAS_RTT_ASM_SUPPORT 0 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() asm VOLATILE ("DMB"); + #endif + #endif + #if (defined __ARM8M_MAINLINE__) + #if (__CORE__ == __ARM8M_MAINLINE__) // Cortex-M33 + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() asm VOLATILE ("DMB"); + #endif + #endif + #if (defined __ARM8EM_MAINLINE__) + #if (__CORE__ == __ARM8EM_MAINLINE__) // Cortex-??? + #define _CORE_HAS_RTT_ASM_SUPPORT 1 + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() asm VOLATILE ("DMB"); + #endif + #endif + #if (defined __ARM7A__) + #if (__CORE__ == __ARM7A__) // Cortex-A 32-bit ARMv7-A + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() asm VOLATILE ("DMB"); + #endif + #endif + #if (defined __ARM7R__) + #if (__CORE__ == __ARM7R__) // Cortex-R 32-bit ARMv7-R + #define _CORE_NEEDS_DMB 1 + #define RTT__DMB() asm VOLATILE ("DMB"); + #endif + #endif +// TBD: __ARM8A__ => Cortex-A 64-bit ARMv8-A +// TBD: __ARM8R__ => Cortex-R 64-bit ARMv8-R #else + // + // Other compilers + // + #define _CC_HAS_RTT_ASM_SUPPORT 0 #define _CORE_HAS_RTT_ASM_SUPPORT 0 #endif // // If IDE and core support the ASM version, enable ASM version by default // + #ifndef _CORE_HAS_RTT_ASM_SUPPORT + #define _CORE_HAS_RTT_ASM_SUPPORT 0 // Default for unknown cores + #endif #if (_CC_HAS_RTT_ASM_SUPPORT && _CORE_HAS_RTT_ASM_SUPPORT) #define RTT_USE_ASM (1) #else @@ -110,6 +230,35 @@ Revision: $Rev: 17697 $ #endif #endif +#ifndef _CORE_NEEDS_DMB + #define _CORE_NEEDS_DMB 0 +#endif + +#ifndef RTT__DMB + #if _CORE_NEEDS_DMB + #error "Don't know how to place inline assembly for DMB" + #else + #define RTT__DMB() + #endif +#endif + +#ifndef SEGGER_RTT_CPU_CACHE_LINE_SIZE + #define SEGGER_RTT_CPU_CACHE_LINE_SIZE (0) // On most target systems where RTT is used, we do not have a CPU cache, therefore 0 is a good default here +#endif + +#ifndef SEGGER_RTT_UNCACHED_OFF + #if SEGGER_RTT_CPU_CACHE_LINE_SIZE + #error "SEGGER_RTT_UNCACHED_OFF must be defined when setting SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #else + #define SEGGER_RTT_UNCACHED_OFF (0) + #endif +#endif +#if RTT_USE_ASM + #if SEGGER_RTT_CPU_CACHE_LINE_SIZE + #error "RTT_USE_ASM is not available if SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" + #endif +#endif + #ifndef SEGGER_RTT_ASM // defined when SEGGER_RTT.h is included from assembly file #include #include @@ -121,6 +270,21 @@ Revision: $Rev: 17697 $ ********************************************************************** */ +// +// Determine how much we must pad the control block to make it a multiple of a cache line in size +// Assuming: U8 = 1B +// U16 = 2B +// U32 = 4B +// U8/U16/U32* = 4B +// +#if SEGGER_RTT_CPU_CACHE_LINE_SIZE // Avoid division by zero in case we do not have any cache + #define SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(NumBytes) (((NumBytes + SEGGER_RTT_CPU_CACHE_LINE_SIZE - 1) / SEGGER_RTT_CPU_CACHE_LINE_SIZE) * SEGGER_RTT_CPU_CACHE_LINE_SIZE) +#else + #define SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(NumBytes) (NumBytes) +#endif +#define SEGGER_RTT__CB_SIZE (16 + 4 + 4 + (SEGGER_RTT_MAX_NUM_UP_BUFFERS * 24) + (SEGGER_RTT_MAX_NUM_DOWN_BUFFERS * 24)) +#define SEGGER_RTT__CB_PADDING (SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(SEGGER_RTT__CB_SIZE) - SEGGER_RTT__CB_SIZE) + /********************************************************************* * * Types @@ -138,7 +302,7 @@ typedef struct { unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty. unsigned WrOff; // Position of next item to be written by either target. volatile unsigned RdOff; // Position of next item to be read by host. Must be volatile since it may be modified by host. - unsigned Flags; // Contains configuration flags + unsigned Flags; // Contains configuration flags. Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. } SEGGER_RTT_BUFFER_UP; // @@ -151,7 +315,7 @@ typedef struct { unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty. volatile unsigned WrOff; // Position of next item to be written by host. Must be volatile since it may be modified by host. unsigned RdOff; // Position of next item to be read by target (down-buffer). - unsigned Flags; // Contains configuration flags + unsigned Flags; // Contains configuration flags. Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT operating mode. } SEGGER_RTT_BUFFER_DOWN; // @@ -165,6 +329,9 @@ typedef struct { int MaxNumDownBuffers; // Initialized to SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (type. 2) SEGGER_RTT_BUFFER_UP aUp[SEGGER_RTT_MAX_NUM_UP_BUFFERS]; // Up buffers, transferring information up from target via debug probe to host SEGGER_RTT_BUFFER_DOWN aDown[SEGGER_RTT_MAX_NUM_DOWN_BUFFERS]; // Down buffers, transferring information down from host via debug probe to target +#if SEGGER_RTT__CB_PADDING + unsigned char aDummy[SEGGER_RTT__CB_PADDING]; +#endif } SEGGER_RTT_CB; /********************************************************************* @@ -214,7 +381,7 @@ unsigned SEGGER_RTT_GetBytesInBuffer (unsigned BufferIndex); // // Function macro for performance optimization // -#define SEGGER_RTT_HASDATA(n) (_SEGGER_RTT.aDown[n].WrOff - _SEGGER_RTT.aDown[n].RdOff) +#define SEGGER_RTT_HASDATA(n) (((SEGGER_RTT_BUFFER_DOWN*)((char*)&_SEGGER_RTT.aDown[n] + SEGGER_RTT_UNCACHED_OFF))->WrOff - ((SEGGER_RTT_BUFFER_DOWN*)((char*)&_SEGGER_RTT.aDown[n] + SEGGER_RTT_UNCACHED_OFF))->RdOff) #if RTT_USE_ASM #define SEGGER_RTT_WriteSkipNoLock SEGGER_RTT_ASM_WriteSkipNoLock @@ -231,7 +398,7 @@ unsigned SEGGER_RTT_ReadUpBufferNoLock (unsigned BufferIndex, void* pDa unsigned SEGGER_RTT_WriteDownBuffer (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); unsigned SEGGER_RTT_WriteDownBufferNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); -#define SEGGER_RTT_HASDATA_UP(n) (_SEGGER_RTT.aUp[n].WrOff - _SEGGER_RTT.aUp[n].RdOff) +#define SEGGER_RTT_HASDATA_UP(n) (((SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[n] + SEGGER_RTT_UNCACHED_OFF))->WrOff - ((SEGGER_RTT_BUFFER_UP*)((char*)&_SEGGER_RTT.aUp[n] + SEGGER_RTT_UNCACHED_OFF))->RdOff) // Access uncached to make sure we see changes made by the J-Link side and all of our changes go into HW directly /********************************************************************* * diff --git a/lib/SEGGER_RTT/RTT/SEGGER_RTT_ASM_ARMv7M.S b/lib/SEGGER_RTT/RTT/SEGGER_RTT_ASM_ARMv7M.S index aec372eec..85c79899e 100644 --- a/lib/SEGGER_RTT/RTT/SEGGER_RTT_ASM_ARMv7M.S +++ b/lib/SEGGER_RTT/RTT/SEGGER_RTT_ASM_ARMv7M.S @@ -23,6 +23,7 @@ Additional information: * ********************************************************************** */ + #define _CCIAR 0 #define _CCCLANG 1 @@ -182,6 +183,9 @@ _LoopCopyStraight: // memcpy(pRing->pBuffer + WrOf SUBS R2,R2,#+1 BNE _LoopCopyStraight _CSDone: +#if _CORE_NEEDS_DMB // Do not slow down cores that do not need a DMB instruction here + DMB // Cortex-M7 may delay memory writes and also change the order in which the writes happen. Therefore, make sure that all buffer writes are finished, before updating the in the struct +#endif STR R0,[R6, #+12] // pRing->WrOff = WrOff + NumBytes; MOVS R0,#+1 POP {R4-R7} @@ -214,6 +218,9 @@ _LoopCopyAfterWrapAround: // memcpy(pRing->pBuffer, pData SUBS R2,R2,#+1 BNE _LoopCopyAfterWrapAround _No2ChunkNeeded: +#if _CORE_NEEDS_DMB // Do not slow down cores that do not need a DMB instruction here + DMB // Cortex-M7 may delay memory writes and also change the order in which the writes happen. Therefore, make sure that all buffer writes are finished, before updating the in the struct +#endif STR R4,[R6, #+12] // pRing->WrOff = NumBytes; => Must be written after copying data because J-Link may read control block asynchronously while writing into buffer MOVS R0,#+1 POP {R4-R7} diff --git a/lib/SEGGER_RTT/RTT/SEGGER_RTT_printf.c b/lib/SEGGER_RTT/RTT/SEGGER_RTT_printf.c deleted file mode 100644 index 4c996b408..000000000 --- a/lib/SEGGER_RTT/RTT/SEGGER_RTT_printf.c +++ /dev/null @@ -1,500 +0,0 @@ -/********************************************************************* -* SEGGER Microcontroller GmbH * -* The Embedded Experts * -********************************************************************** -* * -* (c) 1995 - 2019 SEGGER Microcontroller GmbH * -* * -* www.segger.com Support: support@segger.com * -* * -********************************************************************** -* * -* SEGGER RTT * Real Time Transfer for embedded targets * -* * -********************************************************************** -* * -* All rights reserved. * -* * -* SEGGER strongly recommends to not make any changes * -* to or modify the source code of this software in order to stay * -* compatible with the RTT protocol and J-Link. * -* * -* Redistribution and use in source and binary forms, with or * -* without modification, are permitted provided that the following * -* condition is met: * -* * -* o Redistributions of source code must retain the above copyright * -* notice, this condition and the following disclaimer. * -* * -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * -* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * -* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * -* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * -* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR * -* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * -* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * -* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * -* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * -* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * -* DAMAGE. * -* * -********************************************************************** ----------------------------END-OF-HEADER------------------------------ -File : SEGGER_RTT_printf.c -Purpose : Replacement for printf to write formatted data via RTT -Revision: $Rev: 17697 $ ----------------------------------------------------------------------- -*/ -#include "SEGGER_RTT.h" -#include "SEGGER_RTT_Conf.h" - -/********************************************************************* -* -* Defines, configurable -* -********************************************************************** -*/ - -#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE - #define SEGGER_RTT_PRINTF_BUFFER_SIZE (64) -#endif - -#include -#include - - -#define FORMAT_FLAG_LEFT_JUSTIFY (1u << 0) -#define FORMAT_FLAG_PAD_ZERO (1u << 1) -#define FORMAT_FLAG_PRINT_SIGN (1u << 2) -#define FORMAT_FLAG_ALTERNATE (1u << 3) - -/********************************************************************* -* -* Types -* -********************************************************************** -*/ - -typedef struct { - char* pBuffer; - unsigned BufferSize; - unsigned Cnt; - - int ReturnValue; - - unsigned RTTBufferIndex; -} SEGGER_RTT_PRINTF_DESC; - -/********************************************************************* -* -* Function prototypes -* -********************************************************************** -*/ - -/********************************************************************* -* -* Static code -* -********************************************************************** -*/ -/********************************************************************* -* -* _StoreChar -*/ -static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) { - unsigned Cnt; - - Cnt = p->Cnt; - if ((Cnt + 1u) <= p->BufferSize) { - *(p->pBuffer + Cnt) = c; - p->Cnt = Cnt + 1u; - p->ReturnValue++; - } - // - // Write part of string, when the buffer is full - // - if (p->Cnt == p->BufferSize) { - if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) { - p->ReturnValue = -1; - } else { - p->Cnt = 0u; - } - } -} - -/********************************************************************* -* -* _PrintUnsigned -*/ -static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) { - static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - unsigned Div; - unsigned Digit; - unsigned Number; - unsigned Width; - char c; - - Number = v; - Digit = 1u; - // - // Get actual field width - // - Width = 1u; - while (Number >= Base) { - Number = (Number / Base); - Width++; - } - if (NumDigits > Width) { - Width = NumDigits; - } - // - // Print leading chars if necessary - // - if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) { - if (FieldWidth != 0u) { - if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u)) { - c = '0'; - } else { - c = ' '; - } - while ((FieldWidth != 0u) && (Width < FieldWidth)) { - FieldWidth--; - _StoreChar(pBufferDesc, c); - if (pBufferDesc->ReturnValue < 0) { - break; - } - } - } - } - if (pBufferDesc->ReturnValue >= 0) { - // - // Compute Digit. - // Loop until Digit has the value of the highest digit required. - // Example: If the output is 345 (Base 10), loop 2 times until Digit is 100. - // - while (1) { - if (NumDigits > 1u) { // User specified a min number of digits to print? => Make sure we loop at least that often, before checking anything else (> 1 check avoids problems with NumDigits being signed / unsigned) - NumDigits--; - } else { - Div = v / Digit; - if (Div < Base) { // Is our divider big enough to extract the highest digit from value? => Done - break; - } - } - Digit *= Base; - } - // - // Output digits - // - do { - Div = v / Digit; - v -= Div * Digit; - _StoreChar(pBufferDesc, _aV2C[Div]); - if (pBufferDesc->ReturnValue < 0) { - break; - } - Digit /= Base; - } while (Digit); - // - // Print trailing spaces if necessary - // - if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) { - if (FieldWidth != 0u) { - while ((FieldWidth != 0u) && (Width < FieldWidth)) { - FieldWidth--; - _StoreChar(pBufferDesc, ' '); - if (pBufferDesc->ReturnValue < 0) { - break; - } - } - } - } - } -} - -/********************************************************************* -* -* _PrintInt -*/ -static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) { - unsigned Width; - int Number; - - Number = (v < 0) ? -v : v; - - // - // Get actual field width - // - Width = 1u; - while (Number >= (int)Base) { - Number = (Number / (int)Base); - Width++; - } - if (NumDigits > Width) { - Width = NumDigits; - } - if ((FieldWidth > 0u) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) { - FieldWidth--; - } - - // - // Print leading spaces if necessary - // - if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)) { - if (FieldWidth != 0u) { - while ((FieldWidth != 0u) && (Width < FieldWidth)) { - FieldWidth--; - _StoreChar(pBufferDesc, ' '); - if (pBufferDesc->ReturnValue < 0) { - break; - } - } - } - } - // - // Print sign if necessary - // - if (pBufferDesc->ReturnValue >= 0) { - if (v < 0) { - v = -v; - _StoreChar(pBufferDesc, '-'); - } else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) { - _StoreChar(pBufferDesc, '+'); - } else { - - } - if (pBufferDesc->ReturnValue >= 0) { - // - // Print leading zeros if necessary - // - if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u)) { - if (FieldWidth != 0u) { - while ((FieldWidth != 0u) && (Width < FieldWidth)) { - FieldWidth--; - _StoreChar(pBufferDesc, '0'); - if (pBufferDesc->ReturnValue < 0) { - break; - } - } - } - } - if (pBufferDesc->ReturnValue >= 0) { - // - // Print number without sign - // - _PrintUnsigned(pBufferDesc, (unsigned)v, Base, NumDigits, FieldWidth, FormatFlags); - } - } - } -} - -/********************************************************************* -* -* Public code -* -********************************************************************** -*/ -/********************************************************************* -* -* SEGGER_RTT_vprintf -* -* Function description -* Stores a formatted string in SEGGER RTT control block. -* This data is read by the host. -* -* Parameters -* BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal") -* sFormat Pointer to format string -* pParamList Pointer to the list of arguments for the format string -* -* Return values -* >= 0: Number of bytes which have been stored in the "Up"-buffer. -* < 0: Error -*/ -int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) { - char c; - SEGGER_RTT_PRINTF_DESC BufferDesc; - int v; - unsigned NumDigits; - unsigned FormatFlags; - unsigned FieldWidth; - char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE]; - - BufferDesc.pBuffer = acBuffer; - BufferDesc.BufferSize = SEGGER_RTT_PRINTF_BUFFER_SIZE; - BufferDesc.Cnt = 0u; - BufferDesc.RTTBufferIndex = BufferIndex; - BufferDesc.ReturnValue = 0; - - do { - c = *sFormat; - sFormat++; - if (c == 0u) { - break; - } - if (c == '%') { - // - // Filter out flags - // - FormatFlags = 0u; - v = 1; - do { - c = *sFormat; - switch (c) { - case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break; - case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO; sFormat++; break; - case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN; sFormat++; break; - case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE; sFormat++; break; - default: v = 0; break; - } - } while (v); - // - // filter out field with - // - FieldWidth = 0u; - do { - c = *sFormat; - if ((c < '0') || (c > '9')) { - break; - } - sFormat++; - FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0'); - } while (1); - - // - // Filter out precision (number of digits to display) - // - NumDigits = 0u; - c = *sFormat; - if (c == '.') { - sFormat++; - do { - c = *sFormat; - if ((c < '0') || (c > '9')) { - break; - } - sFormat++; - NumDigits = NumDigits * 10u + ((unsigned)c - '0'); - } while (1); - } - // - // Filter out length modifier - // - c = *sFormat; - do { - if ((c == 'l') || (c == 'h')) { - sFormat++; - c = *sFormat; - } else { - break; - } - } while (1); - // - // Handle specifiers - // - switch (c) { - case 'c': { - char c0; - v = va_arg(*pParamList, int); - c0 = (char)v; - _StoreChar(&BufferDesc, c0); - break; - } - case 'd': - v = va_arg(*pParamList, int); - _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags); - break; - case 'u': - v = va_arg(*pParamList, int); - _PrintUnsigned(&BufferDesc, (unsigned)v, 10u, NumDigits, FieldWidth, FormatFlags); - break; - case 'x': - case 'X': - v = va_arg(*pParamList, int); - _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, NumDigits, FieldWidth, FormatFlags); - break; - case 's': - { - const char * s = va_arg(*pParamList, const char *); - do { - c = *s; - s++; - if (c == '\0') { - break; - } - _StoreChar(&BufferDesc, c); - } while (BufferDesc.ReturnValue >= 0); - } - break; - case 'p': - v = va_arg(*pParamList, int); - _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u); - break; - case '%': - _StoreChar(&BufferDesc, '%'); - break; - default: - break; - } - sFormat++; - } else { - _StoreChar(&BufferDesc, c); - } - } while (BufferDesc.ReturnValue >= 0); - - if (BufferDesc.ReturnValue > 0) { - // - // Write remaining data, if any - // - if (BufferDesc.Cnt != 0u) { - SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt); - } - BufferDesc.ReturnValue += (int)BufferDesc.Cnt; - } - return BufferDesc.ReturnValue; -} - -/********************************************************************* -* -* SEGGER_RTT_printf -* -* Function description -* Stores a formatted string in SEGGER RTT control block. -* This data is read by the host. -* -* Parameters -* BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal") -* sFormat Pointer to format string, followed by the arguments for conversion -* -* Return values -* >= 0: Number of bytes which have been stored in the "Up"-buffer. -* < 0: Error -* -* Notes -* (1) Conversion specifications have following syntax: -* %[flags][FieldWidth][.Precision]ConversionSpecifier -* (2) Supported flags: -* -: Left justify within the field width -* +: Always print sign extension for signed conversions -* 0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision -* Supported conversion specifiers: -* c: Print the argument as one char -* d: Print the argument as a signed integer -* u: Print the argument as an unsigned integer -* x: Print the argument as an hexadecimal integer -* s: Print the string pointed to by the argument -* p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.) -*/ -int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) { - int r; - va_list ParamList; - - va_start(ParamList, sFormat); - r = SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList); - va_end(ParamList); - return r; -} -/*************************** End of file ****************************/ diff --git a/lib/SEGGER_RTT/Syscalls/SEGGER_RTT_Syscalls_GCC.c b/lib/SEGGER_RTT/Syscalls/SEGGER_RTT_Syscalls_GCC.c deleted file mode 100644 index 6bf670a02..000000000 --- a/lib/SEGGER_RTT/Syscalls/SEGGER_RTT_Syscalls_GCC.c +++ /dev/null @@ -1,120 +0,0 @@ -/********************************************************************* -* SEGGER Microcontroller GmbH * -* The Embedded Experts * -********************************************************************** -* * -* (c) 1995 - 2019 SEGGER Microcontroller GmbH * -* * -* www.segger.com Support: support@segger.com * -* * -********************************************************************** -* * -* SEGGER RTT * Real Time Transfer for embedded targets * -* * -********************************************************************** -* * -* All rights reserved. * -* * -* SEGGER strongly recommends to not make any changes * -* to or modify the source code of this software in order to stay * -* compatible with the RTT protocol and J-Link. * -* * -* Redistribution and use in source and binary forms, with or * -* without modification, are permitted provided that the following * -* condition is met: * -* * -* o Redistributions of source code must retain the above copyright * -* notice, this condition and the following disclaimer. * -* * -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * -* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * -* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * -* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * -* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR * -* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * -* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * -* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * -* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * -* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * -* DAMAGE. * -* * -********************************************************************** ----------------------------END-OF-HEADER------------------------------ -File : SEGGER_RTT_Syscalls_GCC.c -Purpose : Low-level functions for using printf() via RTT in GCC. - To use RTT for printf output, include this file in your - application. -Revision: $Rev: 17697 $ ----------------------------------------------------------------------- -*/ -#if (defined __GNUC__) && !(defined __SES_ARM) && !(defined __CROSSWORKS_ARM) - -#include // required for _write_r -#include "SEGGER_RTT.h" - - -/********************************************************************* -* -* Types -* -********************************************************************** -*/ -// -// If necessary define the _reent struct -// to match the one passed by the used standard library. -// -struct _reent; - -/********************************************************************* -* -* Function prototypes -* -********************************************************************** -*/ -int _write(int file, char *ptr, int len); -int _write_r(struct _reent *r, int file, const void *ptr, int len); - -/********************************************************************* -* -* Global functions -* -********************************************************************** -*/ - -/********************************************************************* -* -* _write() -* -* Function description -* Low-level write function. -* libc subroutines will use this system routine for output to all files, -* including stdout. -* Write data via RTT. -*/ -int _write(int file, char *ptr, int len) { - (void) file; /* Not used, avoid warning */ - SEGGER_RTT_Write(0, ptr, len); - return len; -} - -/********************************************************************* -* -* _write_r() -* -* Function description -* Low-level reentrant write function. -* libc subroutines will use this system routine for output to all files, -* including stdout. -* Write data via RTT. -*/ -int _write_r(struct _reent *r, int file, const void *ptr, int len) { - (void) file; /* Not used, avoid warning */ - (void) r; /* Not used, avoid warning */ - SEGGER_RTT_Write(0, ptr, len); - return len; -} - -#endif -/****** End Of File *************************************************/ diff --git a/lib/SEGGER_RTT/Syscalls/SEGGER_RTT_Syscalls_IAR.c b/lib/SEGGER_RTT/Syscalls/SEGGER_RTT_Syscalls_IAR.c deleted file mode 100644 index 4c76752b3..000000000 --- a/lib/SEGGER_RTT/Syscalls/SEGGER_RTT_Syscalls_IAR.c +++ /dev/null @@ -1,115 +0,0 @@ -/********************************************************************* -* SEGGER Microcontroller GmbH * -* The Embedded Experts * -********************************************************************** -* * -* (c) 1995 - 2019 SEGGER Microcontroller GmbH * -* * -* www.segger.com Support: support@segger.com * -* * -********************************************************************** -* * -* SEGGER RTT * Real Time Transfer for embedded targets * -* * -********************************************************************** -* * -* All rights reserved. * -* * -* SEGGER strongly recommends to not make any changes * -* to or modify the source code of this software in order to stay * -* compatible with the RTT protocol and J-Link. * -* * -* Redistribution and use in source and binary forms, with or * -* without modification, are permitted provided that the following * -* condition is met: * -* * -* o Redistributions of source code must retain the above copyright * -* notice, this condition and the following disclaimer. * -* * -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * -* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * -* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * -* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * -* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR * -* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * -* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * -* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * -* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * -* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * -* DAMAGE. * -* * -********************************************************************** ----------------------------END-OF-HEADER------------------------------ -File : SEGGER_RTT_Syscalls_IAR.c -Purpose : Low-level functions for using printf() via RTT in IAR. - To use RTT for printf output, include this file in your - application and set the Library Configuration to Normal. -Revision: $Rev: 17697 $ ----------------------------------------------------------------------- -*/ -#ifdef __IAR_SYSTEMS_ICC__ - -// -// Since IAR EWARM V8 and EWRX V4, yfuns.h is considered as deprecated and LowLevelIOInterface.h -// shall be used instead. To not break any compatibility with older compiler versions, we have a -// version check in here. -// -#if ((defined __ICCARM__) && (__VER__ >= 8000000)) || ((defined __ICCRX__) && (__VER__ >= 400)) - #include -#else - #include -#endif - -#include "SEGGER_RTT.h" -#pragma module_name = "?__write" - -/********************************************************************* -* -* Function prototypes -* -********************************************************************** -*/ -size_t __write(int handle, const unsigned char * buffer, size_t size); - -/********************************************************************* -* -* Global functions -* -********************************************************************** -*/ -/********************************************************************* -* -* __write() -* -* Function description -* Low-level write function. -* Standard library subroutines will use this system routine -* for output to all files, including stdout. -* Write data via RTT. -*/ -size_t __write(int handle, const unsigned char * buffer, size_t size) { - (void) handle; /* Not used, avoid warning */ - SEGGER_RTT_Write(0, (const char*)buffer, size); - return size; -} - -/********************************************************************* -* -* __write_buffered() -* -* Function description -* Low-level write function. -* Standard library subroutines will use this system routine -* for output to all files, including stdout. -* Write data via RTT. -*/ -size_t __write_buffered(int handle, const unsigned char * buffer, size_t size) { - (void) handle; /* Not used, avoid warning */ - SEGGER_RTT_Write(0, (const char*)buffer, size); - return size; -} - -#endif -/****** End Of File *************************************************/ diff --git a/lib/SEGGER_RTT/Syscalls/SEGGER_RTT_Syscalls_KEIL.c b/lib/SEGGER_RTT/Syscalls/SEGGER_RTT_Syscalls_KEIL.c deleted file mode 100644 index ba9772d3e..000000000 --- a/lib/SEGGER_RTT/Syscalls/SEGGER_RTT_Syscalls_KEIL.c +++ /dev/null @@ -1,386 +0,0 @@ -/********************************************************************* -* SEGGER Microcontroller GmbH * -* The Embedded Experts * -********************************************************************** -* * -* (c) 1995 - 2019 SEGGER Microcontroller GmbH * -* * -* www.segger.com Support: support@segger.com * -* * -********************************************************************** -* * -* SEGGER RTT * Real Time Transfer for embedded targets * -* * -********************************************************************** -* * -* All rights reserved. * -* * -* SEGGER strongly recommends to not make any changes * -* to or modify the source code of this software in order to stay * -* compatible with the RTT protocol and J-Link. * -* * -* Redistribution and use in source and binary forms, with or * -* without modification, are permitted provided that the following * -* condition is met: * -* * -* o Redistributions of source code must retain the above copyright * -* notice, this condition and the following disclaimer. * -* * -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * -* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * -* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * -* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * -* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR * -* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * -* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * -* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * -* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * -* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * -* DAMAGE. * -* * -********************************************************************** ----------------------------END-OF-HEADER------------------------------ -File : RTT_Syscalls_KEIL.c -Purpose : Retargeting module for KEIL MDK-CM3. - Low-level functions for using printf() via RTT -Revision: $Rev: 17697 $ ----------------------------------------------------------------------- -*/ -#ifdef __CC_ARM - -#include -#include -#include -#include -#include - -#include "SEGGER_RTT.h" -/********************************************************************* -* -* #pragmas -* -********************************************************************** -*/ -#pragma import(__use_no_semihosting) - -#ifdef _MICROLIB - #pragma import(__use_full_stdio) -#endif - -/********************************************************************* -* -* Defines non-configurable -* -********************************************************************** -*/ - -/* Standard IO device handles - arbitrary, but any real file system handles must be - less than 0x8000. */ -#define STDIN 0x8001 // Standard Input Stream -#define STDOUT 0x8002 // Standard Output Stream -#define STDERR 0x8003 // Standard Error Stream - -/********************************************************************* -* -* Public const -* -********************************************************************** -*/ -#if __ARMCC_VERSION < 5000000 -//const char __stdin_name[] = "STDIN"; -const char __stdout_name[] = "STDOUT"; -const char __stderr_name[] = "STDERR"; -#endif - -/********************************************************************* -* -* Public code -* -********************************************************************** -*/ - -/********************************************************************* -* -* _ttywrch -* -* Function description: -* Outputs a character to the console -* -* Parameters: -* c - character to output -* -*/ -void _ttywrch(int c) { - fputc(c, stdout); // stdout - fflush(stdout); -} - -/********************************************************************* -* -* _sys_open -* -* Function description: -* Opens the device/file in order to do read/write operations -* -* Parameters: -* sName - sName of the device/file to open -* OpenMode - This parameter is currently ignored -* -* Return value: -* != 0 - Handle to the object to open, otherwise -* == 0 -"device" is not handled by this module -* -*/ -FILEHANDLE _sys_open(const char * sName, int OpenMode) { - (void)OpenMode; - // Register standard Input Output devices. - if (strcmp(sName, __stdout_name) == 0) { - return (STDOUT); - } else if (strcmp(sName, __stderr_name) == 0) { - return (STDERR); - } else - return (0); // Not implemented -} - -/********************************************************************* -* -* _sys_close -* -* Function description: -* Closes the handle to the open device/file -* -* Parameters: -* hFile - Handle to a file opened via _sys_open -* -* Return value: -* 0 - device/file closed -* -*/ -int _sys_close(FILEHANDLE hFile) { - (void)hFile; - return 0; // Not implemented -} - -/********************************************************************* -* -* _sys_write -* -* Function description: -* Writes the data to an open handle. -* Currently this function only outputs data to the console -* -* Parameters: -* hFile - Handle to a file opened via _sys_open -* pBuffer - Pointer to the data that shall be written -* NumBytes - Number of bytes to write -* Mode - The Mode that shall be used -* -* Return value: -* Number of bytes *not* written to the file/device -* -*/ -int _sys_write(FILEHANDLE hFile, const unsigned char * pBuffer, unsigned NumBytes, int Mode) { - int r = 0; - - (void)Mode; - if (hFile == STDOUT) { - SEGGER_RTT_Write(0, (const char*)pBuffer, NumBytes); - return 0; - } - return r; -} - -/********************************************************************* -* -* _sys_read -* -* Function description: -* Reads data from an open handle. -* Currently this modules does nothing. -* -* Parameters: -* hFile - Handle to a file opened via _sys_open -* pBuffer - Pointer to buffer to store the read data -* NumBytes - Number of bytes to read -* Mode - The Mode that shall be used -* -* Return value: -* Number of bytes read from the file/device -* -*/ -int _sys_read(FILEHANDLE hFile, unsigned char * pBuffer, unsigned NumBytes, int Mode) { - (void)hFile; - (void)pBuffer; - (void)NumBytes; - (void)Mode; - return (0); // Not implemented -} - -/********************************************************************* -* -* _sys_istty -* -* Function description: -* This function shall return whether the opened file -* is a console device or not. -* -* Parameters: -* hFile - Handle to a file opened via _sys_open -* -* Return value: -* 1 - Device is a console -* 0 - Device is not a console -* -*/ -int _sys_istty(FILEHANDLE hFile) { - if (hFile > 0x8000) { - return (1); - } - return (0); // Not implemented -} - -/********************************************************************* -* -* _sys_seek -* -* Function description: -* Seeks via the file to a specific position -* -* Parameters: -* hFile - Handle to a file opened via _sys_open -* Pos - -* -* Return value: -* int - -* -*/ -int _sys_seek(FILEHANDLE hFile, long Pos) { - (void)hFile; - (void)Pos; - return (0); // Not implemented -} - -/********************************************************************* -* -* _sys_ensure -* -* Function description: -* -* -* Parameters: -* hFile - Handle to a file opened via _sys_open -* -* Return value: -* int - -* -*/ -int _sys_ensure(FILEHANDLE hFile) { - (void)hFile; - return (-1); // Not implemented -} - -/********************************************************************* -* -* _sys_flen -* -* Function description: -* Returns the length of the opened file handle -* -* Parameters: -* hFile - Handle to a file opened via _sys_open -* -* Return value: -* Length of the file -* -*/ -long _sys_flen(FILEHANDLE hFile) { - (void)hFile; - return (0); // Not implemented -} - -/********************************************************************* -* -* _sys_tmpnam -* -* Function description: -* This function converts the file number fileno for a temporary -* file to a unique filename, for example, tmp0001. -* -* Parameters: -* pBuffer - Pointer to a buffer to store the name -* FileNum - file number to convert -* MaxLen - Size of the buffer -* -* Return value: -* 1 - Error -* 0 - Success -* -*/ -int _sys_tmpnam(char * pBuffer, int FileNum, unsigned MaxLen) { - (void)pBuffer; - (void)FileNum; - (void)MaxLen; - return (1); // Not implemented -} - -/********************************************************************* -* -* _sys_command_string -* -* Function description: -* This function shall execute a system command. -* -* Parameters: -* cmd - Pointer to the command string -* len - Length of the string -* -* Return value: -* == NULL - Command was not successfully executed -* == sCmd - Command was passed successfully -* -*/ -char * _sys_command_string(char * cmd, int len) { - (void)len; - return cmd; // Not implemented -} - -/********************************************************************* -* -* _sys_exit -* -* Function description: -* This function is called when the application returns from main -* -* Parameters: -* ReturnCode - Return code from the main function -* -* -*/ -void _sys_exit(int ReturnCode) { - (void)ReturnCode; - while (1); // Not implemented -} - -#if __ARMCC_VERSION >= 5000000 -/********************************************************************* -* -* stdout_putchar -* -* Function description: -* Put a character to the stdout -* -* Parameters: -* ch - Character to output -* -* -*/ -int stdout_putchar(int ch) { - (void)ch; - return ch; // Not implemented -} -#endif - -#endif -/*************************** End of file ****************************/ diff --git a/lib/SEGGER_RTT/Syscalls/SEGGER_RTT_Syscalls_SES.c b/lib/SEGGER_RTT/Syscalls/SEGGER_RTT_Syscalls_SES.c deleted file mode 100644 index 5ce8457e1..000000000 --- a/lib/SEGGER_RTT/Syscalls/SEGGER_RTT_Syscalls_SES.c +++ /dev/null @@ -1,247 +0,0 @@ -/********************************************************************* -* SEGGER Microcontroller GmbH * -* The Embedded Experts * -********************************************************************** -* * -* (c) 1995 - 2019 SEGGER Microcontroller GmbH * -* * -* www.segger.com Support: support@segger.com * -* * -********************************************************************** -* * -* SEGGER RTT * Real Time Transfer for embedded targets * -* * -********************************************************************** -* * -* All rights reserved. * -* * -* SEGGER strongly recommends to not make any changes * -* to or modify the source code of this software in order to stay * -* compatible with the RTT protocol and J-Link. * -* * -* Redistribution and use in source and binary forms, with or * -* without modification, are permitted provided that the following * -* condition is met: * -* * -* o Redistributions of source code must retain the above copyright * -* notice, this condition and the following disclaimer. * -* * -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * -* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * -* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * -* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * -* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR * -* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * -* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * -* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * -* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * -* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * -* DAMAGE. * -* * -********************************************************************** ----------------------------END-OF-HEADER------------------------------ -File : SEGGER_RTT_Syscalls_SES.c -Purpose : Reimplementation of printf, puts and __getchar using RTT - in SEGGER Embedded Studio. - To use RTT for printf output, include this file in your - application. -Revision: $Rev: 18539 $ ----------------------------------------------------------------------- -*/ -#if (defined __SES_ARM) || (defined __SES_RISCV) || (defined __CROSSWORKS_ARM) - -#include "SEGGER_RTT.h" -#include -#include -#include "limits.h" -#include "__libc.h" -#include "__vfprintf.h" - -/********************************************************************* -* -* Defines, configurable -* -********************************************************************** -*/ -// -// Select string formatting implementation. -// -// RTT printf formatting -// - Configurable stack usage. (SEGGER_RTT_PRINTF_BUFFER_SIZE in SEGGER_RTT_Conf.h) -// - No maximum string length. -// - Limited conversion specifiers and flags. (See SEGGER_RTT_printf.c) -// Standard library printf formatting -// - Configurable formatting capabilities. -// - Full conversion specifier and flag support. -// - Maximum string length has to be known or (slightly) slower character-wise output. -// -// #define PRINTF_USE_SEGGER_RTT_FORMATTING 0 // Use standard library formatting -// #define PRINTF_USE_SEGGER_RTT_FORMATTING 1 // Use RTT formatting -// -#ifndef PRINTF_USE_SEGGER_RTT_FORMATTING - #define PRINTF_USE_SEGGER_RTT_FORMATTING 0 -#endif -// -// If using standard library formatting, -// select maximum output string buffer size or character-wise output. -// -// #define PRINTF_BUFFER_SIZE 0 // Use character-wise output -// #define PRINTF_BUFFER_SIZE 128 // Default maximum string length -// -#ifndef PRINTF_BUFFER_SIZE - #define PRINTF_BUFFER_SIZE 128 -#endif - -#if PRINTF_USE_SEGGER_RTT_FORMATTING // Use SEGGER RTT formatting implementation -/********************************************************************* -* -* Function prototypes -* -********************************************************************** -*/ -int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList); - -/********************************************************************* -* -* Global functions, printf -* -********************************************************************** -*/ -/********************************************************************* -* -* printf() -* -* Function description -* print a formatted string using RTT and SEGGER RTT formatting. -*/ -int printf(const char *fmt,...) { - int n; - va_list args; - - va_start (args, fmt); - n = SEGGER_RTT_vprintf(0, fmt, &args); - va_end(args); - return n; -} - -#elif PRINTF_BUFFER_SIZE == 0 // Use standard library formatting with character-wise output - -/********************************************************************* -* -* Static functions -* -********************************************************************** -*/ -static int _putchar(int x, __printf_tag_ptr ctx) { - (void)ctx; - SEGGER_RTT_Write(0, (char *)&x, 1); - return x; -} - -/********************************************************************* -* -* Global functions, printf -* -********************************************************************** -*/ -/********************************************************************* -* -* printf() -* -* Function description -* print a formatted string character-wise, using RTT and standard -* library formatting. -*/ -int printf(const char *fmt, ...) { - int n; - va_list args; - __printf_t iod; - - va_start(args, fmt); - iod.string = 0; - iod.maxchars = INT_MAX; - iod.output_fn = _putchar; - SEGGER_RTT_LOCK(); - n = __vfprintf(&iod, fmt, args); - SEGGER_RTT_UNLOCK(); - va_end(args); - return n; -} - -#else // Use standard library formatting with static buffer - -/********************************************************************* -* -* Global functions, printf -* -********************************************************************** -*/ -/********************************************************************* -* -* printf() -* -* Function description -* print a formatted string using RTT and standard library formatting. -*/ -int printf(const char *fmt,...) { - int n; - char aBuffer[PRINTF_BUFFER_SIZE]; - va_list args; - - va_start (args, fmt); - n = vsnprintf(aBuffer, sizeof(aBuffer), fmt, args); - if (n > (int)sizeof(aBuffer)) { - SEGGER_RTT_Write(0, aBuffer, sizeof(aBuffer)); - } else if (n > 0) { - SEGGER_RTT_Write(0, aBuffer, n); - } - va_end(args); - return n; -} -#endif - -/********************************************************************* -* -* Global functions -* -********************************************************************** -*/ -/********************************************************************* -* -* puts() -* -* Function description -* print a string using RTT. -*/ -int puts(const char *s) { - return SEGGER_RTT_WriteString(0, s); -} - -/********************************************************************* -* -* __putchar() -* -* Function description -* Write one character via RTT. -*/ -int __putchar(int x, __printf_tag_ptr ctx) { - (void)ctx; - SEGGER_RTT_Write(0, (char *)&x, 1); - return x; -} - -/********************************************************************* -* -* __getchar() -* -* Function description -* Wait for and get a character via RTT. -*/ -int __getchar() { - return SEGGER_RTT_WaitKey(); -} - -#endif -/****** End Of File *************************************************/ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 09f41c9ab..ce4486ecd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,6 +32,8 @@ function(add_tinyusb TARGET) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/hid/hid_host.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/msc/msc_host.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/class/vendor/vendor_host.c + # typec + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/typec/utcd.c ) target_include_directories(${TARGET} PUBLIC ${CMAKE_CURRENT_FUNCTION_LIST_DIR} @@ -98,7 +100,3 @@ endif() target_link_libraries(${TINYUSB_TARGET} PUBLIC ${TINYUSB_CONFIG_TARGET} ) - -# export target name -# set(TINYUSB_TARGET ${TINYUSB_TARGET} PARENT_SCOPE) -# set(TINYUSB_CONFIG_TARGET ${TINYUSB_CONFIG_TARGET} PARENT_SCOPE) diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 48f765674..f89467e75 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -197,10 +197,17 @@ #define TUP_DCD_ENDPOINT_MAX 9 #elif TU_CHECK_MCU(OPT_MCU_STM32G4) + // Device controller #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 + + // TypeC controller + #define TUP_USBIP_TYPEC_STM32 + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_TYPEC_RHPORTS_NUM 1 + #elif TU_CHECK_MCU(OPT_MCU_STM32G0) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index 39a2d4564..fab680989 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -232,6 +232,9 @@ enum { #define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2) +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ typedef enum { XFER_RESULT_SUCCESS = 0, @@ -474,9 +477,10 @@ typedef struct TU_ATTR_PACKED uint16_t bcdDFUVersion; } tusb_desc_dfu_functional_t; -/*------------------------------------------------------------------*/ -/* Types - *------------------------------------------------------------------*/ +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + typedef struct TU_ATTR_PACKED{ union { struct TU_ATTR_PACKED { diff --git a/src/device/dcd.h b/src/device/dcd.h index f82b8633d..4e9cfd5d5 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -189,6 +189,7 @@ TU_ATTR_WEAK bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t l // Configure and enable an ISO endpoint according to descriptor TU_ATTR_WEAK bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); + //--------------------------------------------------------------------+ // Event API (implemented by stack) //--------------------------------------------------------------------+ diff --git a/src/device/usbd.c b/src/device/usbd.c index 409a5ec10..44c2530ce 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -252,9 +252,19 @@ static inline usbd_class_driver_t const * get_driver(uint8_t drvid) drvid -= _app_driver_count; } + // when there is no built-in drivers BUILTIN_DRIVER_COUNT = 0 will cause -Wtype-limits warning +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" +#endif + // Built-in drivers if (drvid < BUILTIN_DRIVER_COUNT) return &_usbd_driver[drvid]; +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + return NULL; } diff --git a/src/host/usbh.c b/src/host/usbh.c index 6159044ab..98e959a12 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -724,7 +724,7 @@ uint8_t* usbh_get_enum_buf(void) void usbh_int_set(bool enabled) { - // TODO all host controller if multiple is used + // TODO all host controller if multiple are used since they shared the same event queue if (enabled) { hcd_int_enable(_usbh_controller); diff --git a/src/portable/st/typec/typec_stm32.c b/src/portable/st/typec/typec_stm32.c new file mode 100644 index 000000000..b09dc5bae --- /dev/null +++ b/src/portable/st/typec/typec_stm32.c @@ -0,0 +1,369 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "tusb_option.h" +#include "typec/tcd.h" + +#if CFG_TUC_ENABLED && defined(TUP_USBIP_TYPEC_STM32) + +#include "common/tusb_common.h" + +#if CFG_TUSB_MCU == OPT_MCU_STM32G4 + #include "stm32g4xx.h" + #include "stm32g4xx_ll_dma.h" // for UCPD REQID +#else + #error "Unsupported STM32 family" +#endif + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +enum { + IMR_ATTACHED = UCPD_IMR_TXMSGDISCIE | UCPD_IMR_TXMSGSENTIE | UCPD_IMR_TXMSGABTIE | UCPD_IMR_TXUNDIE | + UCPD_IMR_RXHRSTDETIE | UCPD_IMR_RXOVRIE | UCPD_IMR_RXMSGENDIE | UCPD_IMR_RXORDDETIE | + UCPD_IMR_HRSTDISCIE | UCPD_IMR_HRSTSENTIE | UCPD_IMR_FRSEVTIE +}; + +#define PHY_SYNC1 0x18u +#define PHY_SYNC2 0x11u +#define PHY_SYNC3 0x06u +#define PHY_RST1 0x07u +#define PHY_RST2 0x19u +#define PHY_EOP 0x0Du + +#define PHY_ORDERED_SET_SOP (PHY_SYNC1 | (PHY_SYNC1<<5u) | (PHY_SYNC1<<10u) | (PHY_SYNC2<<15u)) // SOP Ordered set coding +#define PHY_ORDERED_SET_SOP_P (PHY_SYNC1 | (PHY_SYNC1<<5u) | (PHY_SYNC3<<10u) | (PHY_SYNC3<<15u)) // SOP' Ordered set coding +#define PHY_ORDERED_SET_SOP_PP (PHY_SYNC1 | (PHY_SYNC3<<5u) | (PHY_SYNC1<<10u) | (PHY_SYNC3<<15u)) // SOP'' Ordered set coding +#define PHY_ORDERED_SET_HARD_RESET (PHY_RST1 | (PHY_RST1<<5u) | (PHY_RST1<<10u) | (PHY_RST2<<15u )) // Hard Reset Ordered set coding +#define PHY_ORDERED_SET_CABLE_RESET (PHY_RST1 | (PHY_SYNC1<<5u) | (PHY_RST1<<10u) | (PHY_SYNC3<<15u)) // Cable Reset Ordered set coding +#define PHY_ORDERED_SET_SOP_P_DEBUG (PHY_SYNC1 | (PHY_RST2<<5u) | (PHY_RST2<<10u) | (PHY_SYNC3<<15u)) // SOP' Debug Ordered set coding +#define PHY_ORDERED_SET_SOP_PP_DEBUG (PHY_SYNC1 | (PHY_RST2<<5u) | (PHY_SYNC3<<10u) | (PHY_SYNC2<<15u)) // SOP'' Debug Ordered set coding + + +static uint8_t const* _rx_buf; +static uint8_t const* _tx_pending_buf; +static uint16_t _tx_pending_bytes; +static uint16_t _tx_xferring_bytes; + +static pd_header_t _good_crc = { + .msg_type = PD_CTRL_GOOD_CRC, + .data_role = 0, // UFP + .specs_rev = PD_REV_20, + .power_role = 0, // Sink + .msg_id = 0, + .n_data_obj = 0, + .extended = 0 +}; + +// address of DMA channel rx, tx for each port +#define CFG_TUC_STM32_DMA { { DMA1_Channel1_BASE, DMA1_Channel2_BASE } } + +//--------------------------------------------------------------------+ +// DMA +//--------------------------------------------------------------------+ + +static const uint32_t _dma_addr_arr[TUP_TYPEC_RHPORTS_NUM][2] = CFG_TUC_STM32_DMA; + +TU_ATTR_ALWAYS_INLINE static inline uint32_t dma_get_addr(uint8_t rhport, bool is_rx) { + return _dma_addr_arr[rhport][is_rx ? 0 : 1]; +} + +static void dma_init(uint8_t rhport, bool is_rx) { + uint32_t dma_addr = dma_get_addr(rhport, is_rx); + DMA_Channel_TypeDef* dma_ch = (DMA_Channel_TypeDef*) dma_addr; + uint32_t req_id; + + if (is_rx) { + // Peripheral -> Memory, Memory inc, 8-bit, High priority + dma_ch->CCR = DMA_CCR_MINC | DMA_CCR_PL_1; + dma_ch->CPAR = (uint32_t) &UCPD1->RXDR; + + req_id = LL_DMAMUX_REQ_UCPD1_RX; + } else { + // Memory -> Peripheral, Memory inc, 8-bit, High priority + dma_ch->CCR = DMA_CCR_MINC | DMA_CCR_PL_1 | DMA_CCR_DIR; + dma_ch->CPAR = (uint32_t) &UCPD1->TXDR; + + req_id = LL_DMAMUX_REQ_UCPD1_TX; + } + + // find and set up mux channel TODO support mcu with multiple DMAMUXs + enum { + CH_DIFF = DMA1_Channel2_BASE - DMA1_Channel1_BASE + }; + uint32_t mux_ch_num; + + #ifdef DMA2_BASE + if (dma_addr > DMA2_BASE) { + mux_ch_num = 8 * ((dma_addr - DMA2_Channel1_BASE) / CH_DIFF); + } else + #endif + { + mux_ch_num = (dma_addr - DMA1_Channel1_BASE) / CH_DIFF; + } + + DMAMUX_Channel_TypeDef* mux_ch = DMAMUX1_Channel0 + mux_ch_num; + + uint32_t mux_ccr = mux_ch->CCR & ~(DMAMUX_CxCR_DMAREQ_ID); + mux_ccr |= req_id; + mux_ch->CCR = mux_ccr; +} + +TU_ATTR_ALWAYS_INLINE static inline void dma_start(uint8_t rhport, bool is_rx, void const* buf, uint16_t len) { + DMA_Channel_TypeDef* dma_ch = (DMA_Channel_TypeDef*) dma_get_addr(rhport, is_rx); + + dma_ch->CMAR = (uint32_t) buf; + dma_ch->CNDTR = len; + dma_ch->CCR |= DMA_CCR_EN; +} + +TU_ATTR_ALWAYS_INLINE static inline void dma_stop(uint8_t rhport, bool is_rx) { + DMA_Channel_TypeDef* dma_ch = (DMA_Channel_TypeDef*) dma_get_addr(rhport, is_rx); + dma_ch->CCR &= ~DMA_CCR_EN; +} + +TU_ATTR_ALWAYS_INLINE static inline bool dma_enabled(uint8_t rhport, bool is_rx) { + DMA_Channel_TypeDef* dma_ch = (DMA_Channel_TypeDef*) dma_get_addr(rhport, is_rx); + return dma_ch->CCR & DMA_CCR_EN; +} + +TU_ATTR_ALWAYS_INLINE static inline void dma_tx_start(uint8_t rhport, void const* buf, uint16_t len) { + UCPD1->TX_ORDSET = PHY_ORDERED_SET_SOP; + UCPD1->TX_PAYSZ = len; + dma_start(rhport, false, buf, len); + UCPD1->CR |= UCPD_CR_TXSEND; +} + +TU_ATTR_ALWAYS_INLINE static inline void dma_tx_stop(uint8_t rhport) { + dma_stop(rhport, false); +} + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +bool tcd_init(uint8_t rhport, uint32_t port_type) { + (void) rhport; + + // Init DMA for RX, TX + dma_init(rhport, true); + dma_init(rhport, false); + + // Initialization phase: CFG1, detect all SOPs + UCPD1->CFG1 = (0x0d << UCPD_CFG1_HBITCLKDIV_Pos) | (0x10 << UCPD_CFG1_IFRGAP_Pos) | (0x07 << UCPD_CFG1_TRANSWIN_Pos) | + (0x01 << UCPD_CFG1_PSC_UCPDCLK_Pos) | (0x1f << UCPD_CFG1_RXORDSETEN_Pos); + UCPD1->CFG1 |= UCPD_CFG1_UCPDEN; + + // General programming sequence (with UCPD configured then enabled) + if (port_type == TUSB_TYPEC_PORT_SNK) { + // Set analog mode enable both CC Phy + UCPD1->CR = (0x01 << UCPD_CR_ANAMODE_Pos) | (UCPD_CR_CCENABLE_0 | UCPD_CR_CCENABLE_1); + + // Read Voltage State on CC1 & CC2 fore initial state + uint32_t v_cc[2]; + v_cc[0] = (UCPD1->SR >> UCPD_SR_TYPEC_VSTATE_CC1_Pos) & 0x03; + v_cc[1] = (UCPD1->SR >> UCPD_SR_TYPEC_VSTATE_CC2_Pos) & 0x03; + + TU_LOG1("Initial VState CC1 = %u, CC2 = %u\r\n", v_cc[0], v_cc[1]); + + // Enable CC1 & CC2 Interrupt + UCPD1->IMR = UCPD_IMR_TYPECEVT1IE | UCPD_IMR_TYPECEVT2IE; + } + + // Disable dead battery in PWR's CR3 + PWR->CR3 |= PWR_CR3_UCPD_DBDIS; + + return true; +} + +// Enable interrupt +void tcd_int_enable (uint8_t rhport) { + (void) rhport; + NVIC_EnableIRQ(UCPD1_IRQn); +} + +// Disable interrupt +void tcd_int_disable(uint8_t rhport) { + (void) rhport; + NVIC_DisableIRQ(UCPD1_IRQn); +} + +bool tcd_msg_receive(uint8_t rhport, uint8_t* buffer, uint16_t total_bytes) { + _rx_buf = buffer; + dma_start(rhport, true, buffer, total_bytes); + return true; +} + +bool tcd_msg_send(uint8_t rhport, uint8_t const* buffer, uint16_t total_bytes) { + (void) rhport; + + if (dma_enabled(rhport, false)) { + // DMA is busy, probably sending GoodCRC, save as pending TX + _tx_pending_buf = buffer; + _tx_pending_bytes = total_bytes; + }else { + // DMA is free, start sending + _tx_pending_buf = NULL; + _tx_pending_bytes = 0; + + _tx_xferring_bytes = total_bytes; + dma_tx_start(rhport, buffer, total_bytes); + } + + return true; +} + +void tcd_int_handler(uint8_t rhport) { + (void) rhport; + + uint32_t sr = UCPD1->SR; + sr &= UCPD1->IMR; + + if (sr & (UCPD_SR_TYPECEVT1 | UCPD_SR_TYPECEVT2)) { + uint32_t v_cc[2]; + v_cc[0] = (UCPD1->SR >> UCPD_SR_TYPEC_VSTATE_CC1_Pos) & 0x03; + v_cc[1] = (UCPD1->SR >> UCPD_SR_TYPEC_VSTATE_CC2_Pos) & 0x03; + + TU_LOG3("VState CC1 = %u, CC2 = %u\n", v_cc[0], v_cc[1]); + + uint32_t cr = UCPD1->CR; + + // TODO only support SNK for now, required highest voltage for now + // Enable PHY on active CC and disable Rd on other CC + // FIXME somehow CC2 is vstate is not correct, always 1 even not attached. + // on DPOW1 board, it is connected to PA10 (USBPD_DBCC2), we probably miss something. + if ((sr & UCPD_SR_TYPECEVT1) && (v_cc[0] == 3)) { + TU_LOG3("Attach CC1\n"); + cr &= ~(UCPD_CR_PHYCCSEL | UCPD_CR_CCENABLE); + cr |= UCPD_CR_PHYRXEN | UCPD_CR_CCENABLE_0; + } else if ((sr & UCPD_SR_TYPECEVT2) && (v_cc[1] == 3)) { + TU_LOG3("Attach CC2\n"); + cr &= ~UCPD_CR_CCENABLE; + cr |= (UCPD_CR_PHYCCSEL | UCPD_CR_PHYRXEN | UCPD_CR_CCENABLE_1); + } else { + TU_LOG3("Detach\n"); + cr &= ~UCPD_CR_PHYRXEN; + cr |= UCPD_CR_CCENABLE_0 | UCPD_CR_CCENABLE_1; + } + + if (cr & UCPD_CR_PHYRXEN) { + // Attached + UCPD1->IMR |= IMR_ATTACHED; + UCPD1->CFG1 |= UCPD_CFG1_RXDMAEN | UCPD_CFG1_TXDMAEN; + }else { + // Detached + UCPD1->CFG1 &= ~(UCPD_CFG1_RXDMAEN | UCPD_CFG1_TXDMAEN); + UCPD1->IMR &= ~IMR_ATTACHED; + } + + // notify stack + tcd_event_cc_changed(rhport, v_cc[0], v_cc[1], true); + + UCPD1->CR = cr; + + // ack + UCPD1->ICR = UCPD_ICR_TYPECEVT1CF | UCPD_ICR_TYPECEVT2CF; + } + + //------------- RX -------------// + if (sr & UCPD_SR_RXORDDET) { + // SOP: Start of Packet. + TU_LOG3("SOP\n"); + // UCPD1->RX_ORDSET & UCPD_RX_ORDSET_RXORDSET_Msk; + + // ack + UCPD1->ICR = UCPD_ICR_RXORDDETCF; + } + + // Received full message + if (sr & UCPD_SR_RXMSGEND) { + TU_LOG3("RX MSG END\n"); + + // stop TX + dma_stop(rhport, true); + + uint8_t result; + + if (!(sr & UCPD_SR_RXERR)) { + // response with good crc + _good_crc.msg_id = ((pd_header_t const*) _rx_buf)->msg_id; + dma_tx_start(rhport, &_good_crc, 2); + + result = XFER_RESULT_SUCCESS; + }else { + // CRC failed + result = XFER_RESULT_FAILED; + } + + // notify stack + tcd_event_rx_complete(rhport, UCPD1->RX_PAYSZ, result, true); + + // ack + UCPD1->ICR = UCPD_ICR_RXMSGENDCF; + } + + if (sr & UCPD_SR_RXOVR) { + TU_LOG3("RXOVR\n"); + // ack + UCPD1->ICR = UCPD_ICR_RXOVRCF; + } + + //------------- TX -------------// + // All tx events: complete and error + if (sr & (UCPD_SR_TXMSGSENT | (UCPD_SR_TXMSGDISC | UCPD_SR_TXMSGABT | UCPD_SR_TXUND))) { + // force TX stop + dma_tx_stop(rhport); + + uint16_t const xferred_bytes = _tx_xferring_bytes - UCPD1->TX_PAYSZ; + uint8_t result; + + if ( sr & UCPD_SR_TXMSGSENT ) { + TU_LOG3("TX MSG SENT\n"); + result = XFER_RESULT_SUCCESS; + // ack + UCPD1->ICR = UCPD_ICR_TXMSGSENTCF; + }else { + TU_LOG3("TX Error\n"); + result = XFER_RESULT_FAILED; + // ack + UCPD1->ICR = UCPD_SR_TXMSGDISC | UCPD_SR_TXMSGABT | UCPD_SR_TXUND; + } + + // start pending TX if any + if (_tx_pending_buf && _tx_pending_bytes ) { + // Start the pending TX + dma_tx_start(rhport, _tx_pending_buf, _tx_pending_bytes); + + // clear pending + _tx_pending_buf = NULL; + _tx_pending_bytes = 0; + } + + // notify stack + tcd_event_tx_complete(rhport, xferred_bytes, result, true); + } +} + +#endif diff --git a/src/tusb.h b/src/tusb.h index b776d7d01..0b87b1969 100644 --- a/src/tusb.h +++ b/src/tusb.h @@ -40,6 +40,11 @@ #include "class/hid/hid.h" +//------------- TypeC -------------// +#if CFG_TUC_ENABLED + #include "typec/utcd.h" +#endif + //------------- HOST -------------// #if CFG_TUH_ENABLED #include "host/usbh.h" diff --git a/src/tusb_option.h b/src/tusb_option.h index 948c9edf3..bb669e693 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -483,6 +483,16 @@ #endif +//--------------------------------------------------------------------+ +// TypeC Options (Default) +//--------------------------------------------------------------------+ + +#ifndef CFG_TUC_ENABLED +#define CFG_TUC_ENABLED 0 + +#define tuc_int_handler(_p) +#endif + //------------------------------------------------------------------ // Configuration Validation //------------------------------------------------------------------ diff --git a/src/typec/pd_types.h b/src/typec/pd_types.h new file mode 100644 index 000000000..1b2968f65 --- /dev/null +++ b/src/typec/pd_types.h @@ -0,0 +1,237 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_PD_TYPES_H_ +#define _TUSB_PD_TYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "common/tusb_compiler.h" + +// Start of all packed definitions for compiler without per-type packed +TU_ATTR_PACKED_BEGIN +TU_ATTR_BIT_FIELD_ORDER_BEGIN + +//--------------------------------------------------------------------+ +// TYPE-C +//--------------------------------------------------------------------+ + +typedef enum { + TUSB_TYPEC_PORT_SRC, + TUSB_TYPEC_PORT_SNK, + TUSB_TYPEC_PORT_DRP +} tusb_typec_port_type_t; + +enum { + PD_CTRL_RESERVED = 0, // 0b00000: 0 + PD_CTRL_GOOD_CRC, // 0b00001: 1 + PD_CTRL_GO_TO_MIN, // 0b00010: 2 + PD_CTRL_ACCEPT, // 0b00011: 3 + PD_CTRL_REJECT, // 0b00100: 4 + PD_CTRL_PING, // 0b00101: 5 + PD_CTRL_PS_READY, // 0b00110: 6 + PD_CTRL_GET_SOURCE_CAP, // 0b00111: 7 + PD_CTRL_GET_SINK_CAP, // 0b01000: 8 + PD_CTRL_DR_SWAP, // 0b01001: 9 + PD_CTRL_PR_SWAP, // 0b01010: 10 + PD_CTRL_VCONN_SWAP, // 0b01011: 11 + PD_CTRL_WAIT, // 0b01100: 12 + PD_CTRL_SOFT_RESET, // 0b01101: 13 + PD_CTRL_DATA_RESET, // 0b01110: 14 + PD_CTRL_DATA_RESET_COMPLETE, // 0b01111: 15 + PD_CTRL_NOT_SUPPORTED, // 0b10000: 16 + PD_CTRL_GET_SOURCE_CAP_EXTENDED, // 0b10001: 17 + PD_CTRL_GET_STATUS, // 0b10010: 18 + PD_CTRL_FR_SWAP, // 0b10011: 19 + PD_CTRL_GET_PPS_STATUS, // 0b10100: 20 + PD_CTRL_GET_COUNTRY_CODES, // 0b10101: 21 + PD_CTRL_GET_SINK_CAP_EXTENDED, // 0b10110: 22 + PD_CTRL_GET_SOURCE_INFO, // 0b10111: 23 + PD_CTRL_REVISION, // 0b11000: 24 +}; + +enum { + PD_DATA_RESERVED = 0, // 0b00000: 0 + PD_DATA_SOURCE_CAP, // 0b00001: 1 + PD_DATA_REQUEST, // 0b00010: 2 + PD_DATA_BIST, // 0b00011: 3 + PD_DATA_SINK_CAP, // 0b00100: 4 + PD_DATA_BATTERY_STATUS, // 0b00101: 5 + PD_DATA_ALERT, // 0b00110: 6 + PD_DATA_GET_COUNTRY_INFO, // 0b00111: 7 + PD_DATA_ENTER_USB, // 0b01000: 8 + PD_DATA_EPR_REQUEST, // 0b01001: 9 + PD_DATA_EPR_MODE, // 0b01010: 10 + PD_DATA_SRC_INFO, // 0b01011: 11 + PD_DATA_REVISION, // 0b01100: 12 + PD_DATA_RESERVED_13, // 0b01101: 13 + PD_DATA_RESERVED_14, // 0b01110: 14 + PD_DATA_VENDOR_DEFINED, // 0b01111: 15 +}; + +enum { + PD_REV_10 = 0x0, + PD_REV_20 = 0x1, + PD_REV_30 = 0x2, +}; + +enum { + PD_DATA_ROLE_UFP = 0x0, + PD_DATA_ROLE_DFP = 0x1, +}; + +enum { + PD_POWER_ROLE_SINK = 0x0, + PD_POWER_ROLE_SOURCE = 0x1, +}; + +typedef struct TU_ATTR_PACKED { + uint16_t msg_type : 5; // [0:4] + uint16_t data_role : 1; // [5] SOP only: 0 UFP, 1 DFP + uint16_t specs_rev : 2; // [6:7] + uint16_t power_role : 1; // [8] SOP only: 0 Sink, 1 Source + uint16_t msg_id : 3; // [9:11] + uint16_t n_data_obj : 3; // [12:14] + uint16_t extended : 1; // [15] +} pd_header_t; +TU_VERIFY_STATIC(sizeof(pd_header_t) == 2, "size is not correct"); + +typedef struct TU_ATTR_PACKED { + uint16_t data_size : 9; // [0:8] + uint16_t reserved : 1; // [9] + uint16_t request_chunk : 1; // [10] + uint16_t chunk_number : 4; // [11:14] + uint16_t chunked : 1; // [15] +} pd_header_extended_t; +TU_VERIFY_STATIC(sizeof(pd_header_extended_t) == 2, "size is not correct"); + +//--------------------------------------------------------------------+ +// Source Capability +//--------------------------------------------------------------------+ + +// All table references are from USBPD Specification rev3.1 version 1.8 +enum { + PD_PDO_TYPE_FIXED = 0, // Vmin = Vmax + PD_PDO_TYPE_BATTERY, + PD_PDO_TYPE_VARIABLE, // non-battery + PD_PDO_TYPE_APDO, // Augmented Power Data Object +}; + +// Fixed Power Data Object (PDO) table 6-9 +typedef struct TU_ATTR_PACKED { + uint32_t current_max_10ma : 10; // [9..0] Max current in 10mA unit + uint32_t voltage_50mv : 10; // [19..10] Voltage in 50mV unit + uint32_t current_peak : 2; // [21..20] Peak current + uint32_t reserved : 1; // [22] Reserved + uint32_t epr_mode_capable : 1; // [23] epr_mode_capable + uint32_t unchunked_ext_msg_support : 1; // [24] UnChunked Extended Message Supported + uint32_t dual_role_data : 1; // [25] Dual Role Data + uint32_t usb_comm_capable : 1; // [26] USB Communications Capable + uint32_t unconstrained_power : 1; // [27] Unconstrained Power + uint32_t usb_suspend_supported : 1; // [28] USB Suspend Supported + uint32_t dual_role_power : 1; // [29] Dual Role Power + uint32_t type : 2; // [30] Fixed Supply type = PD_PDO_TYPE_FIXED +} pd_pdo_fixed_t; +TU_VERIFY_STATIC(sizeof(pd_pdo_fixed_t) == 4, "Invalid size"); + +// Battery Power Data Object (PDO) table 6-12 +typedef struct TU_ATTR_PACKED { + uint32_t power_max_250mw : 10; // [9..0] Max allowable power in 250mW unit + uint32_t voltage_min_50mv : 10; // [19..10] Minimum voltage in 50mV unit + uint32_t voltage_max_50mv : 10; // [29..20] Maximum voltage in 50mV unit + uint32_t type : 2; // [31..30] Battery type = PD_PDO_TYPE_BATTERY +} pd_pdo_battery_t; +TU_VERIFY_STATIC(sizeof(pd_pdo_battery_t) == 4, "Invalid size"); + +// Variable Power Data Object (PDO) table 6-11 +typedef struct TU_ATTR_PACKED { + uint32_t current_max_10ma : 10; // [9..0] Max current in 10mA unit + uint32_t voltage_min_50mv : 10; // [19..10] Minimum voltage in 50mV unit + uint32_t voltage_max_50mv : 10; // [29..20] Maximum voltage in 50mV unit + uint32_t type : 2; // [31..30] Variable Supply type = PD_PDO_TYPE_VARIABLE +} pd_pdo_variable_t; +TU_VERIFY_STATIC(sizeof(pd_pdo_variable_t) == 4, "Invalid size"); + +// Augmented Power Data Object (PDO) table 6-13 +typedef struct TU_ATTR_PACKED { + uint32_t current_max_50ma : 7; // [6..0] Max current in 50mA unit + uint32_t reserved1 : 1; // [7] Reserved + uint32_t voltage_min_100mv : 8; // [15..8] Minimum Voltage in 100mV unit + uint32_t reserved2 : 1; // [16] Reserved + uint32_t voltage_max_100mv : 8; // [24..17] Maximum Voltage in 100mV unit + uint32_t reserved3 : 2; // [26..25] Reserved + uint32_t pps_power_limited : 1; // [27] PPS Power Limited + uint32_t spr_programmable : 2; // [29..28] SPR Programmable Power Supply + uint32_t type : 2; // [31..30] Augmented Power Data Object = PD_PDO_TYPE_APDO +} pd_pdo_apdo_t; +TU_VERIFY_STATIC(sizeof(pd_pdo_apdo_t) == 4, "Invalid size"); + +//--------------------------------------------------------------------+ +// Request +//--------------------------------------------------------------------+ + +typedef struct TU_ATTR_PACKED { + uint32_t current_extremum_10ma : 10; // [9..0] Max (give back = 0) or Min (give back = 1) current in 10mA unit + uint32_t current_operate_10ma : 10; // [19..10] Operating current in 10mA unit + uint32_t reserved : 2; // [21..20] Reserved + uint32_t epr_mode_capable : 1; // [22] EPR mode capable + uint32_t unchunked_ext_msg_support : 1; // [23] UnChunked Extended Message Supported + uint32_t no_usb_suspend : 1; // [24] No USB Suspend + uint32_t usb_comm_capable : 1; // [25] USB Communications Capable + uint32_t capability_mismatch : 1; // [26] Capability Mismatch + uint32_t give_back_flag : 1; // [27] GiveBack Flag: 0 = Max, 1 = Min + uint32_t object_position : 4; // [31..28] Object Position +} pd_rdo_fixed_variable_t; +TU_VERIFY_STATIC(sizeof(pd_rdo_fixed_variable_t) == 4, "Invalid size"); + +typedef struct TU_ATTR_PACKED { + uint32_t power_extremum_250mw : 10; // [9..0] Max (give back = 0) or Min (give back = 1) operating power in 250mW unit + uint32_t power_operate_250mw : 10; // [19..10] Operating power in 250mW unit + uint32_t reserved : 2; // [21..20] Reserved + uint32_t epr_mode_capable : 1; // [22] EPR mode capable + uint32_t unchunked_ext_msg_support : 1; // [23] UnChunked Extended Message Supported + uint32_t no_usb_suspend : 1; // [24] No USB Suspend + uint32_t usb_comm_capable : 1; // [25] USB Communications Capable + uint32_t capability_mismatch : 1; // [26] Capability Mismatch + uint32_t give_back_flag : 1; // [27] GiveBack Flag: 0 = Max, 1 = Min + uint32_t object_position : 4; // [31..28] Object Position +} pd_rdo_battery_t; +TU_VERIFY_STATIC(sizeof(pd_rdo_battery_t) == 4, "Invalid size"); + + +TU_ATTR_PACKED_END // End of all packed definitions +TU_ATTR_BIT_FIELD_ORDER_END + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/typec/tcd.h b/src/typec/tcd.h new file mode 100644 index 000000000..86499c951 --- /dev/null +++ b/src/typec/tcd.h @@ -0,0 +1,143 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Ha Thach (thach@tinyusb.org) for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_TCD_H_ +#define _TUSB_TCD_H_ + +#include "common/tusb_common.h" +#include "pd_types.h" + +#include "osal/osal.h" +#include "common/tusb_fifo.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +enum { + TCD_EVENT_INVALID = 0, + TCD_EVENT_CC_CHANGED, + TCD_EVENT_RX_COMPLETE, + TCD_EVENT_TX_COMPLETE, +}; + +typedef struct TU_ATTR_PACKED { + uint8_t rhport; + uint8_t event_id; + + union { + struct { + uint8_t cc_state[2]; + } cc_changed; + + struct TU_ATTR_PACKED { + uint16_t result : 2; + uint16_t xferred_bytes : 14; + } xfer_complete; + }; + +} tcd_event_t;; + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +// Initialize controller +bool tcd_init(uint8_t rhport, uint32_t port_type); + +// Enable interrupt +void tcd_int_enable (uint8_t rhport); + +// Disable interrupt +void tcd_int_disable(uint8_t rhport); + +// Interrupt Handler +void tcd_int_handler(uint8_t rhport); + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +bool tcd_msg_receive(uint8_t rhport, uint8_t* buffer, uint16_t total_bytes); +bool tcd_msg_send(uint8_t rhport, uint8_t const* buffer, uint16_t total_bytes); + +//--------------------------------------------------------------------+ +// Event API (implemented by stack) +// Called by TCD to notify stack +//--------------------------------------------------------------------+ + +extern void tcd_event_handler(tcd_event_t const * event, bool in_isr); + +TU_ATTR_ALWAYS_INLINE static inline +void tcd_event_cc_changed(uint8_t rhport, uint8_t cc1, uint8_t cc2, bool in_isr) { + tcd_event_t event = { + .rhport = rhport, + .event_id = TCD_EVENT_CC_CHANGED, + .cc_changed = { + .cc_state = {cc1, cc2 } + } + }; + + tcd_event_handler(&event, in_isr); +} + +TU_ATTR_ALWAYS_INLINE static inline +void tcd_event_rx_complete(uint8_t rhport, uint16_t xferred_bytes, uint8_t result, bool in_isr) { + tcd_event_t event = { + .rhport = rhport, + .event_id = TCD_EVENT_RX_COMPLETE, + .xfer_complete = { + .xferred_bytes = xferred_bytes, + .result = result + } + }; + + tcd_event_handler(&event, in_isr); +} + +TU_ATTR_ALWAYS_INLINE static inline +void tcd_event_tx_complete(uint8_t rhport, uint16_t xferred_bytes, uint8_t result, bool in_isr) { + tcd_event_t event = { + .rhport = rhport, + .event_id = TCD_EVENT_TX_COMPLETE, + .xfer_complete = { + .xferred_bytes = xferred_bytes, + .result = result + } + }; + + tcd_event_handler(&event, in_isr); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/typec/utcd.c b/src/typec/utcd.c new file mode 100644 index 000000000..831df1fe8 --- /dev/null +++ b/src/typec/utcd.c @@ -0,0 +1,219 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Ha Thach (thach@tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUC_ENABLED + +#include "tcd.h" +#include "utcd.h" + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +// Debug level of USBD +#define UTCD_DEBUG 2 +#define TU_LOG_UTCD(...) TU_LOG(UTCD_DEBUG, __VA_ARGS__) + +// Event queue +// utcd_int_set() is used as mutex in OS NONE config +void utcd_int_set(bool enabled); +OSAL_QUEUE_DEF(utcd_int_set, _utcd_qdef, CFG_TUC_TASK_QUEUE_SZ, tcd_event_t); +tu_static osal_queue_t _utcd_q; + +// if stack is initialized +static bool _utcd_inited = false; + +// if port is initialized +static bool _port_inited[TUP_TYPEC_RHPORTS_NUM]; + +// Max possible PD size is 262 bytes +static uint8_t _rx_buf[64] TU_ATTR_ALIGNED(4); +static uint8_t _tx_buf[64] TU_ATTR_ALIGNED(4); + +bool utcd_msg_send(uint8_t rhport, pd_header_t const* header, void const* data); +bool parse_msg_data(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end); +bool parse_msg_control(uint8_t rhport, pd_header_t const* header); + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ +bool tuc_inited(uint8_t rhport) { + return _utcd_inited && _port_inited[rhport]; +} + +bool tuc_init(uint8_t rhport, uint32_t port_type) { + // Initialize stack + if (!_utcd_inited) { + tu_memclr(_port_inited, sizeof(_port_inited)); + + _utcd_q = osal_queue_create(&_utcd_qdef); + TU_ASSERT(_utcd_q != NULL); + + _utcd_inited = true; + } + + // skip if port already initialized + if ( _port_inited[rhport] ) { + return true; + } + + TU_LOG_UTCD("UTCD init on port %u\r\n", rhport); + TU_LOG_INT(UTCD_DEBUG, sizeof(tcd_event_t)); + + TU_ASSERT(tcd_init(rhport, port_type)); + tcd_int_enable(rhport); + + _port_inited[rhport] = true; + return true; +} + +void tuc_task_ext(uint32_t timeout_ms, bool in_isr) { + (void) in_isr; // not implemented yet + + // Skip if stack is not initialized + if (!_utcd_inited) return; + + // Loop until there is no more events in the queue + while (1) { + tcd_event_t event; + if (!osal_queue_receive(_utcd_q, &event, timeout_ms)) return; + + switch (event.event_id) { + case TCD_EVENT_CC_CHANGED: + break; + + case TCD_EVENT_RX_COMPLETE: + // TODO process message here in ISR, move to thread later + if (event.xfer_complete.result == XFER_RESULT_SUCCESS) { + pd_header_t const* header = (pd_header_t const*) _rx_buf; + + if (header->n_data_obj == 0) { + parse_msg_control(event.rhport, header); + + }else { + uint8_t const* p_end = _rx_buf + event.xfer_complete.xferred_bytes; + uint8_t const * dobj = _rx_buf + sizeof(pd_header_t); + + parse_msg_data(event.rhport, header, dobj, p_end); + } + } + + // prepare for next message + tcd_msg_receive(event.rhport, _rx_buf, sizeof(_rx_buf)); + break; + + case TCD_EVENT_TX_COMPLETE: + break; + + default: break; + } + } +} + +bool parse_msg_data(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end) { + if (tuc_pd_data_received_cb) { + tuc_pd_data_received_cb(rhport, header, dobj, p_end); + } + + return true; +} + +bool parse_msg_control(uint8_t rhport, pd_header_t const* header) { + if (tuc_pd_control_received_cb) { + tuc_pd_control_received_cb(rhport, header); + } + + return true; +} + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +bool utcd_msg_send(uint8_t rhport, pd_header_t const* header, void const* data) { + // copy header + memcpy(_tx_buf, header, sizeof(pd_header_t)); + + // copy data objcet if available + uint16_t const n_data_obj = header->n_data_obj; + if (n_data_obj > 0) { + memcpy(_tx_buf + sizeof(pd_header_t), data, n_data_obj * 4); + } + + return tcd_msg_send(rhport, _tx_buf, sizeof(pd_header_t) + n_data_obj * 4); +} + +bool tuc_msg_request(uint8_t rhport, void const* rdo) { + pd_header_t const header = { + .msg_type = PD_DATA_REQUEST, + .data_role = PD_DATA_ROLE_UFP, + .specs_rev = PD_REV_30, + .power_role = PD_POWER_ROLE_SINK, + .msg_id = 0, + .n_data_obj = 1, + .extended = 0, + }; + + return utcd_msg_send(rhport, &header, rdo); +} + +void tcd_event_handler(tcd_event_t const * event, bool in_isr) { + (void) in_isr; + switch(event->event_id) { + case TCD_EVENT_CC_CHANGED: + if (event->cc_changed.cc_state[0] || event->cc_changed.cc_state[1]) { + // Attach, start receiving + tcd_msg_receive(event->rhport, _rx_buf, sizeof(_rx_buf)); + }else { + // Detach + } + break; + + default: break; + } + + osal_queue_send(_utcd_q, event, in_isr); +} + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ +void utcd_int_set(bool enabled) { + // Disable all controllers since they shared the same event queue + for (uint8_t p = 0; p < TUP_TYPEC_RHPORTS_NUM; p++) { + if ( _port_inited[p] ) { + if (enabled) { + tcd_int_enable(p); + }else { + tcd_int_disable(p); + } + } + } +} + +#endif diff --git a/src/typec/utcd.h b/src/typec/utcd.h new file mode 100644 index 000000000..9fbff9bc6 --- /dev/null +++ b/src/typec/utcd.h @@ -0,0 +1,91 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2023 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_UTCD_H_ +#define _TUSB_UTCD_H_ + +#include "common/tusb_common.h" +#include "pd_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//--------------------------------------------------------------------+ +// TypeC Configuration +//--------------------------------------------------------------------+ + +#ifndef CFG_TUC_TASK_QUEUE_SZ +#define CFG_TUC_TASK_QUEUE_SZ 8 +#endif + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + +// Init typec stack on a port +bool tuc_init(uint8_t rhport, uint32_t port_type); + +// Check if typec port is initialized +bool tuc_inited(uint8_t rhport); + +// Task function should be called in main/rtos loop, extended version of tud_task() +// - timeout_ms: millisecond to wait, zero = no wait, 0xFFFFFFFF = wait forever +// - in_isr: if function is called in ISR +void tuc_task_ext(uint32_t timeout_ms, bool in_isr); + +// Task function should be called in main/rtos loop +TU_ATTR_ALWAYS_INLINE static inline +void tuc_task (void) { + tuc_task_ext(UINT32_MAX, false); +} + +#ifndef _TUSB_TCD_H_ +extern void tcd_int_handler(uint8_t rhport); +#endif + +// Interrupt handler, name alias to TCD +#define tuc_int_handler tcd_int_handler + +//--------------------------------------------------------------------+ +// Callbacks +//--------------------------------------------------------------------+ + +TU_ATTR_WEAK bool tuc_pd_data_received_cb(uint8_t rhport, pd_header_t const* header, uint8_t const* dobj, uint8_t const* p_end); +TU_ATTR_WEAK bool tuc_pd_control_received_cb(uint8_t rhport, pd_header_t const* header); + +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +bool tuc_msg_request(uint8_t rhport, void const* rdo); + + +#ifdef __cplusplus +} +#endif + +#endif