🌱 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ì?
- Cách hoạt động của Semihosting
- Ví dụ sử dụng Semihosting trên STM32
- Link tham khảo
👉 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.
![]() |
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 😊
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