Introduction to On-Chip DebuggingFor embedded systems developers, troubleshooting has traditionally been one of the most challenging aspects of the development process. In the early days, methods like LED blinking, serial port output, and in-circuit emulation (ICE) were the primary debugging tools available. But as microcontrollers became more complex and integrated, these methods proved insufficient, giving rise to a powerful solution: the On-Chip Debug Emulator."Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."— Brian W. KernighanToday's embedded systems are the backbone of countless technologies we rely on daily—from smart home devices and industrial controllers to medical equipment and automotive systems. As these systems grow in complexity, so does the need for sophisticated debugging tools that can provide deep insight into program execution, memory states, and peripheral operations in real-time.If you've found yourself frustrated with:Blind debugging with limited visibility into program executionThe inability to set breakpoints or step through codeTime-consuming debugging cycles that slow down developmentStruggling to identify intermittent bugs that only occur in specific situationsDifficulty debugging timing-sensitive applicationsThen understanding and leveraging on-chip debug emulators will transform your development workflow and significantly reduce time-to-market.In this comprehensive guide, we'll explore the inner workings of on-chip debug emulators, compare leading products on the market, and share best practices that will elevate your debugging capabilities to new heights.What is an On-Chip Debug Emulator?An On-Chip Debug Emulator (OCDE) is a specialized hardware tool that connects to the debug interface built into modern microcontrollers and microprocessors, allowing developers to interact with and control the internal operations of the chip during program execution.Unlike traditional in-circuit emulators that physically replace the target processor, on-chip debug emulators leverage debug modules integrated directly into the silicon of the microcontroller itself. This approach provides non-intrusive access to the processor's internals without significantly impacting the program's execution or requiring extensive hardware modifications.The term "emulator" in this context is somewhat historical and can be misleading. While traditional emulators replaced the target processor entirely, modern on-chip debug emulators don't emulate functionality but rather provide a gateway to access and control the processor's built-in debug features.A typical on-chip debug emulator serves three primary functions:1. Debug InterfaceActs as a bridge between your development computer and the target microcontroller's debug port (typically JTAG or SWD), allowing the IDE to communicate with the processor.2. Flash ProgrammingProvides a mechanism to download application code to the target microcontroller's flash memory, eliminating the need for separate programming hardware.3. Run-Time ControlEnables real-time control of program execution, including breakpoints, step-by-step execution, memory inspection, and register manipulation.By integrating these functions, on-chip debug emulators dramatically streamline the development process, allowing developers to identify and resolve issues faster with greater visibility into the system's operation.Evolution of Debugging TechnologyThe journey to modern on-chip debugging has been marked by significant technological innovations, each addressing the limitations of previous approaches:EraDebugging ApproachLimitationsEarly Embedded SystemsLED blinking, Serial output loggingLimited visibility, Intrusive, Required code modification1980s-1990sIn-Circuit Emulation (ICE)Expensive hardware, Processor-specific pods, Limited speed1990s-2000sROM monitors, Boot-loaded debuggersUsed program memory, Modified execution environment2000s-PresentOn-Chip DebuggingMinimal hardware overhead, Standardized interfacesPresent-FutureAdvanced trace, Non-intrusive profilingIncreasing complexity, Specialized training requiredThe major breakthrough came with the standardization of the JTAG (Joint Test Action Group) interface, officially known as IEEE 1149.1. Originally designed for board-level testing, JTAG provided the perfect foundation for on-chip debugging by offering standardized access to the processor core.Microcontroller manufacturers began integrating dedicated debug modules directly into their chips, providing capabilities like:Hardware breakpoints without modifying codeReal-time memory and register accessSingle-step executionProgram traceToday's advanced on-chip debug emulators build upon these foundations, adding sophisticated features like:Real-time trace with dedicated trace portsComplex breakpoint conditionsData watchpoints triggered by memory operationsPerformance profiling and code coverage analysisPower consumption monitoringThis evolution has transformed debugging from a tedious, error-prone process to a streamlined workflow that gives developers unprecedented visibility into their systems.Technical Architecture and OperationOn-chip debug emulators operate through a carefully orchestrated interaction between hardware and software components, creating a seamless interface between the developer's IDE and the target microcontroller.JTAG Interface and ProtocolAt the heart of most on-chip debugging systems is the JTAG interface, which provides a standardized method for accessing the debug features built into modern processors.The JTAG interface typically uses 4-5 key signals:TCK (Test Clock) - Controls the timing of the interfaceTMS (Test Mode Select) - Controls the JTAG state machineTDI (Test Data In) - Serial data input to the deviceTDO (Test Data Out) - Serial data output from the deviceTRST (Test Reset) - Optional signal to reset the JTAG interfaceJTAG operates through a state machine model, allowing access to multiple test data registers within the device. For debugging purposes, the most important registers include:Instruction Register - Selects the active data register and operation modeBoundary Scan Register - Provides access to I/O pinsBypass Register - Shortens the scan chain for unused devicesDevice ID Register - Contains manufacturer and part identificationDebug Data Registers - Processor-specific registers for debug operationsMore recent microcontrollers also support Serial Wire Debug (SWD), a two-wire alternative to JTAG that reduces pin count while maintaining most debugging capabilities. ARM's debug architecture has evolved to include both interfaces, with SWD becoming increasingly popular in space-constrained applications.Key Hardware ComponentsA typical on-chip debug emulator consists of several key hardware components:USB InterfaceConnects to the development computer, providing power and a communication channel for the debug software.Protocol TranslatorConverts between USB commands and JTAG/SWD signals, often implemented using a microcontroller or FPGA.Level ShiftersAdapts signal voltage levels between the emulator and the target device, supporting various operating voltages.Target InterfacePhysical connector that attaches to the target board's debug header, often with additional signals for power and reset control.On the target microcontroller side, the debug infrastructure typically includes:Debug Access Port (DAP) - The interface that connects to external debuggersDebug Port (DP) - The external interface that accepts JTAG or SWD connectionsAccess Port (AP) - Internal interfaces to various system resourcesBreakpoint Units - Hardware that can halt execution at specified addressesTrace Units - Specialized hardware for capturing execution historyPro Tip:When selecting an on-chip debug emulator, ensure it supports all the debug features of your target processor. Some advanced trace capabilities may require specialized, higher-end emulators with support for trace ports.Essential Features and CapabilitiesModern on-chip debug emulators offer a comprehensive set of features that dramatically enhance the debugging experience. Understanding these capabilities helps developers select the right tool for their specific needs.Basic Debug OperationsHardware Breakpoints - Halt program execution at specific addresses without modifying codeSingle-Step Execution - Execute one instruction at a time to observe program flowMemory & Register Access - View and modify memory contents and CPU registers in real-timeVariable Inspection - Examine variable values within the debug environmentAdvanced Debug OperationsData Watchpoints - Trigger breaks on specific memory operationsComplex Breakpoints - Conditional execution halting based on multiple factorsRun-time Variable Updates - Modify variables without stopping executionCall Stack Analysis - Examine the function call hierarchyProgramming CapabilitiesFlash Programming - Write application code to on-chip flash memorySecure Programming - Support for encrypted programming in security-sensitive applicationsProduction Programming - High-speed programming for manufacturing environmentsConfiguration Programming - Set device fuses and configuration bitsTrace & Analysis FeaturesInstruction Trace - Record execution history for post-mortem analysisData Trace - Track memory access patternsProfiling - Analyze execution time of code segmentsCode Coverage - Determine which code has been executedBeyond these core capabilities, premium emulators often include specialized features like:Power AnalysisMeasure and profile power consumption during different execution phases, essential for battery-powered devices.Real-Time Data ExchangeCommunicate between the debugger and target application without halting execution, enabling advanced instrumentation.OS-Aware DebuggingSpecial support for RTOS-based applications, showing task states, stack usage, and scheduling information."The value of a debugging tool is measured not by its features list, but by the speed with which it helps you identify and resolve unexpected program behavior."— Embedded Systems Best PracticesWhen evaluating emulators, consider which features align most closely with your development challenges and the specific microcontroller family you're working with.Strengths and AdvantagesOn-chip debug emulators offer numerous advantages over traditional debugging methods, making them indispensable tools in modern embedded development:1. Non-Intrusive DebuggingDebug without modifying your application code or affecting real-time behavior, ensuring that what you debug is exactly what will run in production.2. Comprehensive System VisibilityGain deep insights into program flow, memory state, peripheral operation, and CPU register values in real-time, making even the most complex bugs easier to track down.3. Accelerated Development CyclesReduce debugging time dramatically with features like hardware breakpoints, watchpoints, and real-time memory inspection, leading to faster time-to-market.4. Integrated ProgrammingProgram and debug with the same tool, eliminating the need for separate programmers and streamlining the development workflow.5. Unified Development EnvironmentWork within a single IDE that integrates coding, compiling, downloading, and debugging, providing a seamless development experience.These advantages translate into tangible benefits for both individual developers and organizations:For DevelopersFor OrganizationsReduced frustration with hard-to-find bugsShorter development cycles and faster time-to-marketLess time spent on debugging, more on feature developmentLower development costs through increased productivityAbility to tackle more complex applications with confidenceHigher product quality and reliabilityImproved understanding of system behavior through direct observationReduced field failures and customer support issuesSkill development through exposure to advanced debugging techniquesKnowledge retention within the organization"The introduction of on-chip debug capabilities has been one of the most significant advancements in embedded development productivity over the past two decades."— Embedded Systems Conference, 2022Limitations and ConsiderationsWhile on-chip debug emulators offer tremendous benefits, they are not without limitations that developers should be aware of:1. Resource ConstraintsDebug hardware consumes on-chip resources, potentially limiting the number of available breakpoints, watchpoints, and trace capabilities.2. Performance ImpactSome debug operations may affect real-time performance, particularly when using trace or when breakpoints are engaged.3. Limited VisibilityNot all internal states may be observable, particularly for complex peripherals or when code executes from RAM.Important considerations when selecting and using on-chip debug emulators include:Hardware Compatibility:Not all emulators support all microcontroller families. Ensure your chosen emulator is fully compatible with your target device, including support for all debug features you require.Signal Integrity:Debug interfaces operate at relatively high frequencies and can be susceptible to noise and signal integrity issues. Use short, properly terminated connections for reliable operation.Security Implications:Debug interfaces can provide a potential security vulnerability if left enabled in production devices. Consider security features that allow permanent or temporary disabling of debug access.Pro Tip:When designing your PCB, always include a standard debug connector even if you don't anticipate needing it. The minimal board space required is a small price to pay for the ability to debug issues that may arise later in development or even in the field.Top On-Chip Debug EmulatorsThe market offers a range of on-chip debug emulators to suit different requirements and budgets. Here's a comparison of some leading options:Renesas R0E000010KCE00On-chip debugging emulator for RX, RL78, RH850, V850, 78K0R, 78K0, and R8C Family microcontrollers. Provides basic debugging functionality and flash programming capabilities.Key Features: Hardware breakpoints, Memory/register access, Flash programmingInterfaces: JTAG, FINEBest For: Entry-level development with Renesas MCUsView ProductRenesas RTE0T0002LKCE00000RE2 emulator Lite is a compact and cost-effective on-chip debugging emulator for Renesas microcontrollers. Offers enhanced performance over the E1 series.Key Features: Advanced breakpoints, Hot-plug capability, Power measurementInterfaces: JTAG, FINE, SWDBest For: Mid-range development with RX, RL78, and RH850 MCUsView ProductSTMicroelectronics ST-LINK/V2In-circuit debugger and programmer for STM8 and STM32 microcontrollers. Widely used for STM-based development due to its solid performance and low cost.Key Features: Virtual COM port, Mass storage, Hardware breakpointsInterfaces: JTAG, SWD, SWIMBest For: STM8 and STM32 development at all levelsView ProductTexas Instruments XDS110ISO-EVMIsolated debug probe for TI embedded processors. Offers galvanic isolation between host PC and target system, ideal for high-voltage applications.Key Features: Isolation barrier, EnergyTrace technology, High-speed traceInterfaces: JTAG, cJTAGBest For: Professional development with TI processors requiring isolationView ProductEmulatorSupported MCUsKey StrengthsLimitationsPrice RangeRenesas E1Renesas RX, RL78, RH850, V850, 78K, R8CCost-effective, Basic debugging featuresLimited trace capabilities, Lower speed$100-200Renesas E2 LiteRenesas RX, RL78, RH850Improved performance, Power monitoringLimited to Renesas devices$200-300ST-LINK/V2STM8, STM32Excellent integration with STM32CubeIDE, CompactLimited to ST microcontrollers$30-50TI XDS110TI MSP430, C2000, Sitara, SimpleLinkEnergyTrace, Good performanceLimited to TI devices$100-300SEGGER J-LinkARM, Renesas, RISC-V, and many othersBroad compatibility, High performanceHigher cost, Advanced features in premium models only$400-700"The best debug emulator is the one that disappears from your workflow—becoming an invisible extension of your development process rather than a tool you have to consciously manage."When selecting an on-chip debug emulator, consider factors beyond price, such as compatibility with your target devices, integration with your preferred IDE, performance requirements, and the specific debug features you'll need.Best Practices for Effective DebuggingEven with powerful on-chip debug emulators, effective debugging requires methodical approaches and best practices. Here are key strategies to maximize your debugging efficiency:1. Plan Your Debug StrategyDefine what you're looking for before startingConsider the most efficient way to identify the issuePrepare your environment with the right tools and configurations2. Start With a Stable BaselineBegin with code that previously worked correctlyMake incremental changes and test after each changeUse version control to easily return to working states3. Leverage Hardware CapabilitiesUse hardware breakpoints for non-intrusive stoppingSet data watchpoints to monitor variable changesUtilize trace capabilities for complex timing issues4. Combine Multiple ToolsUse oscilloscopes for signal-level verificationEmploy logic analyzers for multi-signal timing analysisMaintain strategic debug print statements in key areasDebug Checklist for Embedded Systems:Verify hardware connections and power levelsConfirm that your emulator is properly connected and recognizedCheck for clock stability and correct frequencyValidate that the correct firmware is loadedTest basic functionality before complex operationsUse strategic breakpoints at function boundariesMonitor critical variables through all execution pathsCheck for memory corruption and stack overflowVerify interrupt timing and handler executionLook for peripheral configuration mismatchesRemember that effective debugging is as much about methodology as it is about tools. Even the most advanced on-chip debug emulator can't replace thoughtful analysis and systematic problem-solving."Debugging is like being the detective in a crime movie where you're also the murderer."— Filipe FortesCommon Misconceptions About On-Chip DebuggingDespite their widespread use, several misconceptions persist about on-chip debugging technology:Misconception #1: "On-chip debugging slows down application execution significantly"Reality: While some debug operations can impact performance, modern on-chip debug modules are designed to minimize interference. When breakpoints are not active, most systems run at full speed.Misconception #2: "In-circuit emulators are the same as on-chip debuggers"Reality: In-circuit emulators traditionally replaced the target processor, while on-chip debuggers work with debug features built into the processor itself. They serve similar purposes but operate quite differently.Misconception #3: "JTAG is only useful for debugging"Reality: JTAG was originally designed for boundary scan testing of PCBs. Debugging is just one application of this versatile interface, which is also used for programming, testing, and even security access.Misconception #4: "More expensive emulators always provide better debugging"Reality: While premium emulators offer advanced features, the "best" emulator depends on your specific needs. For many applications, entry-level emulators provide all necessary functionality at a fraction of the cost.Understanding these realities helps developers make more informed decisions about their debugging tools and approaches.Real-World Application ExamplesThe following case studies illustrate how on-chip debug emulators solve real challenges in embedded development:Case Study: Intermittent Communication FailureChallenge: An IoT device experienced random communication failures that couldn't be reproduced consistently.Debug Approach: Using an on-chip emulator with trace capabilities, the development team captured execution history during both successful and failed communications.Solution: Trace data revealed that an interrupt handler occasionally executed during a critical section of the communication routine, corrupting a buffer. Adding proper critical section protection resolved the issue.Key Tool: Hardware trace buffer with timestamp correlationCase Study: Unexplained System ResetChallenge: A medical device would reset unexpectedly during extended operation with no clear error pattern.Debug Approach: The team used an on-chip emulator to set a data watchpoint on the stack pointer register and monitor memory usage patterns.Solution: The watchpoint triggered when the stack pointer approached a critical boundary during a specific function call sequence. Analysis showed a recursive function was causing stack overflow in rare conditions.Key Tool: Hardware data watchpoints on CPU registersCase Study: Power OptimizationChallenge: A battery-powered sensor node was consuming more power than designed, reducing operational life.Debug Approach: Using an emulator with power profiling capabilities, the team measured current consumption correlated with code execution.Solution: The profile revealed that a peripheral was not entering low-power mode correctly due to a missing register configuration. After fixing the initialization code, power consumption dropped by 60%.Key Tool: Integrated power analysis with code correlationUser Experience: RTOS Task Priority InversionChallenge: A complex industrial controller exhibited occasional UI freezes when under heavy processing load.Debug Approach: The development team used an RTOS-aware on-chip debugger to analyze task states, priorities, and execution timing.Solution: The debugger revealed a classic priority inversion scenario where a low-priority task held a resource needed by a high-priority task while a medium-priority task was running. Implementing priority inheritance in the RTOS configuration resolved the issue.Key Tool: RTOS-aware debugging with task visualizationThese examples demonstrate how on-chip debug emulators provide unique insights that would be difficult or impossible to obtain through other methods, leading to faster resolution of complex issues.Transitioning from Arduino to ESP32As embedded developers advance in their careers, many move from simplified platforms like Arduino to more powerful systems like the ESP32. On-chip debugging becomes especially valuable during this transition.The ESP32 offers significantly more computing power, memory, and integrated peripherals than traditional Arduino boards, but this increased capability comes with greater complexity. On-chip debugging helps bridge this complexity gap by providing:Real-time visibility into the dual-core execution of the ESP32Simplified debugging of WiFi and Bluetooth functionalitiesTools to analyze and optimize power consumption for battery-powered applicationsMemory inspection capabilities to manage the larger but still constrained resourcesFor a comprehensive guide on making this transition smoothly, check out our detailed article: Transitioning from Arduino to ESP32: A Comprehensive Guide.Pro Tip for Arduino-to-ESP32 Transition:When moving from Arduino to ESP32, invest in a quality debug emulator compatible with ESP32's JTAG interface. The time saved during development will quickly outweigh the initial cost, especially when debugging WiFi connectivity issues or multi-core applications.Frequently Asked QuestionsQ: What's the difference between JTAG and SWD debugging interfaces?A: JTAG (IEEE 1149.1) is a standardized 4-5 wire interface that provides comprehensive debug access and supports multiple devices in a scan chain. SWD (Serial Wire Debug) is an ARM-specific 2-wire alternative that offers most of the same capabilities with fewer pins, making it ideal for space-constrained designs. SWD is generally faster for basic operations but may offer fewer advanced features compared to full JTAG.Q: Can I use any on-chip debug emulator with any microcontroller?A: No, compatibility depends on both the debug interface (JTAG, SWD, etc.) and the specific processor architecture. Most emulators are designed to work with particular families of microcontrollers. Some premium emulators (like SEGGER J-Link) support multiple architectures, but you should always check compatibility before purchasing. Additionally, manufacturer-specific extensions may only be supported by the manufacturer's own debugging tools.Q: How many hardware breakpoints can I use simultaneously?A: This depends on the specific microcontroller, not the emulator. Most ARM Cortex-M processors provide 4-8 hardware breakpoints, while other architectures may offer different numbers. When you need more breakpoints than hardware supports, some debug environments will use "software breakpoints" by temporarily modifying the code, but these only work in flash memory and may have limitations.Q: Can on-chip debugging work with optimized release builds?A: Yes, but with limitations. Hardware breakpoints and memory inspection will work with any build, but variable inspection and step-by-step execution may be difficult with highly optimized code due to compiler optimizations like inlining, reordering, and register allocation. For best debugging experience, use debug builds with minimal optimization. For production issues, consider builds with debugging symbols but moderate optimization.Q: Do I need special hardware on my PCB to support on-chip debugging?A: Yes, you need to expose the debug interface pins from your microcontroller to a connector on your PCB. This typically requires a dedicated debug header (like a 10-pin or 20-pin JTAG/SWD connector) or at minimum exposing the essential debug signals (like SWDIO and SWCLK for ARM cores). Many development boards include these connectors by default, but custom PCB designs need to explicitly include them.ConclusionOn-chip debug emulators represent one of the most significant advances in embedded systems development tools, transforming what was once a time-consuming and often frustrating process into a streamlined, efficient workflow.As embedded systems continue to grow in complexity and are deployed in increasingly critical applications, the value of comprehensive debugging capabilities becomes even more pronounced. The ability to observe, control, and analyze system behavior down to the instruction level provides developers with unprecedented insight into their applications.Whether you're working with simple 8-bit microcontrollers or advanced multi-core systems, investing in appropriate debugging tools and developing effective debugging methodologies will pay dividends in reduced development time, improved code quality, and enhanced product reliability.Key takeaways from this guide include:On-chip debug emulators provide non-intrusive access to the processor's internal state through specialized debug modules built into modern microcontrollersJTAG and SWD interfaces are the most common physical connections for debug access, with standardized protocols that support a wide range of operationsThe market offers options ranging from manufacturer-specific entry-level emulators to premium multi-architecture systems with advanced trace and analysis capabilitiesEffective debugging combines the right tools with methodical approaches and best practicesAs you advance in embedded development, sophisticated debugging techniques become increasingly valuable for tackling complex challengesBy embracing the capabilities of modern on-chip debug emulators and developing your debugging skills, you'll not only solve problems more efficiently but also gain deeper insights into system behavior that inform better design decisions for future projects.Have questions or suggestions?We'd love to hear about your experiences with on-chip debugging tools. What challenges have you overcome using these technologies? Are there specific aspects you'd like to learn more about? Share your thoughts in the comments below!Additional ResourcesTo further expand your knowledge about on-chip debugging and embedded systems development:Introduction to On-Chip Debug - Embedded.comA comprehensive overview of on-chip debug technologies and their evolution.JTAG Debugging the ESP32 - MCU on EclipseDetailed tutorial on setting up ESP32 debugging with various tools.What is JTAG and How Can I Use It? - XJTAGDetailed explanation of JTAG technology and its applications.Advanced Debugging with GDB - MemfaultTips and techniques for getting the most out of GDB with embedded targets. .container { max-width: 1140px; margin: 0 auto; padding: 0 20px; } h2, h3, h4, h5 { font-weight: 700; margin-top: 1.5em; margin-bottom: 0.5em; } h2 { font-size: 1.8rem; color: #3498db; border-bottom: 2px solid #eaeaea; padding-bottom: 0.3em; } h3 { font-size: 1.5rem; color: #2980b9; } h4 { font-size: 1.2rem; color: #16a085; } p { margin-bottom: 1em; } .quote-box { background-color: #f7f9fc; border-left: 4px solid #3498db; padding: 15px 20px; margin: 20px 0; border-radius: 0 8px 8px 0; } .feature-box { background-color: #f8f9fa; border-radius: 8px; padding: 20px; margin: 20px 0; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); } .product-card { border: 1px solid #e0e0e0; border-radius: 8px; padding: 15px; margin-bottom: 20px; transition: transform 0.3s ease, box-shadow 0.3s ease; } .product-card:hover { transform: translateY(-5px); box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); } .product-card img { margin: 0 auto 15px; display: block; max-height: 150px; object-fit: contain; } .table-container { overflow-x: auto; margin: 25px 0; } table { width: 100%; border-collapse: collapse; } th, td { padding: 12px 15px; border: 1px solid #e0e0e0; } th { background-color: #f8f9fa; font-weight: 600; } tr:nth-child(even) { background-color: #f8f9fa; } .faq-item { margin-bottom: 15px; border-bottom: 1px solid #eaeaea; padding-bottom: 15px; } .faq-question { font-weight: 600; color: #2c3e50; margin-bottom: 8px; } .faq-answer { color: #555; } .video-container { position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; margin: 25px 0; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } .video-container iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; border-radius: 8px; } .cta-button { display: inline-block; background-color: #3498db; color: white; padding: 10px 20px; border-radius: 5px; text-decoration: none; transition: background-color 0.3s ease; margin: 10px 0; } .cta-button:hover { background-color: #2980b9; } .highlight { background-color: #fffde7; padding: 2px 5px; border-radius: 3px; } .misconception { background-color: #ffebee; border-left: 4px solid #e53935; padding: 15px 20px; margin: 20px 0; border-radius: 0 8px 8px 0; } .pro-tip { background-color: #e8f5e9; border-left: 4px solid #43a047; padding: 15px 20px; margin: 20px 0; border-radius: 0 8px 8px 0; } .toc { background-color: #f8f9fa; border-radius: 8px; padding: 20px; margin: 20px 0; } .toc ul { list-style-type: none; padding-left: 0; } .toc ul ul { padding-left: 20px; } .toc li { margin-bottom: 8px; } .toc a { color: #3498db; text-decoration: none; } .toc a:hover { text-decoration: underline; }
Kynix On 2025-05-10