🌱 Semihosting Là Gì? Hướng Dẫn Debug STM32

🌱 Semihosting Là Gì? Hướng Dẫn Debug STM32

    Khi làm việc với Vi điều khiển, kỹ thuật thường được sử dụng với người lập trình Firmware là Logging, dùng để ghi lại thông tin trong quá trình debug, thực hiện chương trình, có thể ghi lại dưới dạng text. Đối với các Vi điều khiển, việc ghi lại thông tin này thường được thực hiện bằng các giao thức nối tiếp (UART, SPI), giao tiếp dữ liệu vào file text trên máy tính.

    Tuy nhiên cách này lại tiêu tốn tài nguyên của vi điều khiển, đó là giao thức UART hay SPI. Chúng ta có thể sử dụng 1 cơ chế nâng cao hơn, đó là Semihosting.

Mục lục


👉 Semihosting là gì?

    Semihosting là một cơ chế cho phép chương trình chạy trên chip ARM giao tiếp và sử dụng các cơ chế Input/Output trên một host - máy tính đang chạy Debug. Chức năng này có sẵn trên các vi điều khiển ARM Cortex.

    Ví dụ, Vi điều khiển có thể sử dụng một số hàm của thư viện C như printf(), scanf(), fopen(). Điều này rất có ích đối với việc debug, khi chúng ta muốn in giá trị biến hay ô nhớ lên màn hình máy tính.

👉 Cách hoạt động của Semihosting

    Semihosting được thực hiện bằng cách tạm dừng hoạt động của CPU (Debug), sử dụng breakpoint hoặc gửi một lệnh Supervisor Call (SVC 0xAB hoặc SVC 0x123456) - Như hình trên.

    Debugger trên máy tính có thể giao tiếp với Vi điều khiển khi bị tạm dừng bằng cách tác động vào 2 thanh ghi R0 và R1.

ARM Semihosting Machenism
Hình 1: Cơ chế hoạt động của Semihosting

➤ Dưới đây là một số Semihosting Operations:

/* File operations */
SYS_OPEN        EQU 0x01 // Open a file or stream on the host system.
SYS_ISTTY       EQU 0x09 // Check whether a file handle is associated with a file or a stream/terminal such as stdout.
SYS_WRITE       EQU 0x05 // Write to a file or stream.
SYS_READ        EQU 0x06 // Read from a file at the current cursor position.
SYS_CLOSE       EQU 0x02 // Closes a file on the host which has been opened by SYS_OPEN.
SYS_FLEN        EQU 0x0C // Get the length of a file.
SYS_SEEK        EQU 0x0A // Set the file cursor to a given position in a file.
SYS_TMPNAM      EQU 0x0D // Get a temporary absolute file path to create a temporary file.
SYS_REMOVE      EQU 0x0E // Remove a file on the host system. Possibly insecure!
SYS_RENAME      EQU 0x0F // Rename a file on the host system. Possibly insecure!

/* Terminal I/O operations */
SYS_WRITEC      EQU 0x03 // Write one character to the debug terminal.
SYS_WRITE0      EQU 0x04 // Write a 0-terminated string to the debug terminal.
SYS_READC       EQU 0x07 // Read one character from the debug terminal.

/* Time operations */
SYS_CLOCK       EQU 0x10
SYS_ELAPSED     EQU 0x30
SYS_TICKFREQ    EQU 0x31
SYS_TIME        EQU 0x11

/* System/Misc. operations */
SYS_ERRNO       EQU 0x13 // Returns the value of the C library errno variable that is associated with the semihosting implementation.
SYS_GET_CMDLINE EQU 0x15 // Get commandline parameters for the application to run with (argc and argv for main())
SYS_HEAPINFO    EQU 0x16
SYS_ISERROR     EQU 0x08
SYS_SYSTEM      EQU 0x12
    

👉 Ví dụ sử dụng Semihosting trên STM32

    Đối với Vi điều khiển STM32, Semihosting thường được sử dụng cùng OpenOCD.

    Ở ví dụ này mình sử dụng arm-none-eabi-gcc làm Cross Compiler. Các bạn có thể thực hành với Vi điều khiển STM32 và tham khảo một số bài viết liên quan đến Makefile của mình.

💬 Để sử dụng chức năng Semihosting, chúng ta cần thêm một số thư viện trong quá trình Linking:

  • libc.a: Thư viện C chuẩn (newlib cho arm-none-eabi-gcc).
  • librdimon.a: Thư viện libgloss (platform-specific code).

    Để thêm 2 thư viện này, chúng ta cần đảm bảo chúng có trong ổ cài arm-none-eabi-gcc. Và sau đó thêm các option sau vào Linker Options:

  • -lc -lrdimon
  • --specs=rdimon.specs: Để sử dụng version semihost của syscalls.
  • Xóa option -nostartfiles nếu có để cho phép link đến thư viện C chuẩn.

💬 Việc thứ 2 cần làm là gọi hàm initialise_monitor_handles() trong code C để bắt đầu sử dụng các function trong thư viện C chuẩn.

Ví dụ code Semihosting trên STM32F401RE

#include "stm32f4xx.h"
#include 

#define SEMIHOSTING

#ifdef SEMIHOSTING
extern void initialise_monitor_handles(void);
#endif

int main(void) {
    #ifdef SEMIHOSTING
    initialise_monitor_handles();
    #endif

    // Cấu hình LED trên Nucleo-F401RE (PA5)
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
    GPIOA->MODER |= GPIO_MODER_MODER5_0; // Output mode

    int counter = 0;
    while (1) {
        GPIOA->ODR ^= GPIO_ODR_OD5; // Toggle LED
        for (volatile int i = 0; i < 1000000; i++); // Delay

        #ifdef SEMIHOSTING
        printf("Counter: %d\n", counter++);
        #endif
    }
    return 0;
}
    

Giải thích:

  • Cấu hình: Sử dụng STM32F401RE (Nucleo board), LED trên PA5 nhấp nháy.
  • Semihosting: Gọi `initialise_monitor_handles()` để kích hoạt, sau đó dùng `printf` để in giá trị `counter` lên console của OpenOCD.
  • Makefile/Linker: Cần thêm `-lc -lrdimon --specs=rdimon.specs` vào lệnh `arm-none-eabi-gcc`.
  • Debug: Chạy OpenOCD với lệnh như `openocd -f board/st_nucleo_f4.cfg`, sau đó dùng GDB để xem output.
  • Output sẽ hiển thị trên terminal của debugger, ví dụ: "Counter: 0", "Counter: 1", ...

💬 Việc thực hiện Semihosting rất hữu ích khi chúng ta Debug, tuy nhiên không được sử dụng khi chương trình hoàn thiện để run, vì vậy các bạn hãy dùng nó thật hiệu quả để test chương trình và xóa nó khi nạp vào một chương trình hoàn chỉnh (Vì nó làm tăng size code và giảm hiệu suất chương trình khi run).

    Mình sẽ có video hướng dẫn sau!

👉 Link tham khảo

What is Semihosting - developer.arm.com

>>>>>> Follow ngay <<<<<<<

Để nhận được những bài học miễn phí mới nhất nhé 😊
Chúc các bạn học tập tốt 😊

Nguyễn Văn Nghĩa

Mình là một người thích học hỏi và chia sẻ các kiến thức về Nhúng IOT.

1 Nhận xét

  1. Anh đã có video phần này chưa ạ, em rất muốn tham khảo về phần này ạ.

    Trả lờiXóa
Mới hơn Cũ hơn
//