---
tags: My skill
---
# Embedded C 筆記
## I/O
I/O運作處理就是指CPU與I/O之間的溝通
I/O架構有兩種:
1.同步:I/O運作完成後才交回,因此一段時間內只會有一個I/O請求產生。
2.非同步:不等I/O完成,即刻交回,因此在一段時間內,會同時有多個I/O request產生,OS需使用"Device status table"來進行記錄。


在預期 I/O 要求需要大量時間的情況下,例如大型資料庫的重新整理或備份或慢速通訊連結,非同步 I/O 通常是優化處理效率的好方法。 不過,對於相對快速的 I/O 作業,處理核心 I/O 要求和核心訊號的額外負荷可能會讓非同步 I/O 變得較不有用,特別是需要進行許多快速 I/O 作業時。 在此情況下,同步 I/O 會比較好。 如何完成這些工作的機制和實作詳細資料會根據所使用的裝置控制碼類型以及應用程式的特定需求而有所不同。 換句話說,通常有多種方式可以解決問題。
I/O運作分為三種
1.Busy waiting I/O(Polling I/O)
就是當process運行到某部分時會發出I/O request來進行週期性的檢查,I/O只需要將資訊放進暫存器就好了,這是最簡單的溝通方式。
2.Interrupt-driven I/O
這就是上一篇interrupt有提到的,當有I/O裝置需要,便會利用interrupt來通知CPU。
3.DMA (Direct Memory Access)
就是提供一個控制器來負責I/O設備與記憶體間的資料傳輸,使CPU不需要參與,CPU便能擁有更多時間在process執行。
## 中斷種類
中斷的種類有分為三種:外部中斷(External Interrupt)、內部中斷(Internal Interrupt)與軟體中斷(Software Interrupt)。
外部中斷就是由CPU以外的周邊元件所發出的,例如I/O interrupt就是由輸出入裝置所引發的中斷。
內部中斷是指CPU本身所引發的,像除以0就會導致內部中斷。
軟體中斷是當使用者在運行程式時如果需要作業系統提供服務會發出中斷通知OS執行對應的service routine
## 物件導向
Object
1. 參與程式的單位
2. 為變數,會占用memory
3. dynamic會隨執行過程而動態改變
Class
1. ADT
2. 靜態單位不參與程式執行
3. blueprint
UML圖範例
class Circle {
private:
double radius;
Point center;
public:
setRadius(double radius);
setCenter(Point center);
double getArea();
double getCircumfrence();
};

O.O.的四大特性
1. Abstraction
1. Encapsulation
1. Inheritance
1. Polymorphism
dynamic binding 程式執行期間才決定呼叫哪個子類別中的同名fun
上述行為稱overriding
而overloading是透過傳入參數的數量或型態不同乘載fun,且不是每個語言都資源overload
```clike=
#include <stdio.h>
#include <stdlib.h>
/* forward declaration */
typedef struct object Object;
typedef int (*func_t)(Object *);
struct object {
int a, b;
func_t add, sub;
};
static int add_impl(Object *self) { // method
return self->a + self->b;
}
static int sub_impl(Object *self) { // method
return self->a - self->b;
}
// & : address of
// * : value of // indirect access
int init_object(Object **self) { // call-by-value
if (NULL == (*self = malloc(sizeof(Object)))) return -1;
(*self)->a = 0; (*self)->b = 0;
(*self)->add = add_impl; (*self)->sub = sub_impl;
return 0;
}
int main(int argc, char *argv[])
{
Object *o = NULL;
init_object(&o);
o->a = 9922; o->b = 5566;
printf("add = %d, sub = %d\n", o->add(o), o->sub(o));
return 0;
}
```
```clike=
#include <stdio.h>
#include <stdlib.h>
/* forward declaration */
typedef struct object* obj_handle;
typedef int (*func_t)(object *);
struct object {
int a, b;
func_t add, sub;
};
static int add_impl(object *self) { // method
return self->a + self->b;
}
static int sub_impl(object *self) { // method
return self->a - self->b;
}
// & : address of
// * : value of // indirect access
handle init_object(void *pMemory,const size_t numBytes)
{
obj_handle handle;
if(numBytes < sizeof(object))
return((obj_handle)NULL);
// assign the handle
handle = (obj_handle)pMemory;
handle->a = 0;
handle->b = 0;
handle->add = add_impl;
handle->sub = sub_impl;
return handle;
}
int main(int argc, char *argv[])
{
object o;
obj_handle o_handle;
o_handle = init_object(&o,sizeof(object));
o_handle->a = 9922; o_handle->b = 5566;
printf("add = %d, sub = %d\n", o_handle->add(o_handle), o_handle->sub(o_handle));
return 0;
}
```
## Acknowledge Interrupt:
2/28
## 暫存器操作底層功能
void* 型態的指標沒有任何型態資訊,只用來儲存位址,不可以使用 * 運算子對 void* 型態指標提取值,而必須轉型至對應的型態,例如:
```cpp
// initialize the ADC
obj->adcHandle = ADC_init((void *)ADC_BASE_ADDR,sizeof(ADC_Obj));
// current sampled last
ADC_Handle ADC_init(void *pMemory,const size_t numBytes)
{
ADC_Handle adcHandle;
if(numBytes < sizeof(ADC_Obj))
return((ADC_Handle)NULL);
// assign the handle
adcHandle = (ADC_Handle)pMemory;
return(adcHandle);
} // end of ADC_init() function
void ADC_powerDown(ADC_Handle adcHandle)
{
ADC_Obj *adc = (ADC_Obj *)adcHandle;
ENABLE_PROTECTED_REGISTER_WRITE_MODE;//asm(" EALLOW")
// clear the bits
adc->ADCCTL1 &= (~ADC_ADCCTL1_ADCPWDN_BITS);//&=
DISABLE_PROTECTED_REGISTER_WRITE_MODE;//asm(" EDIS")
return;
} // end of ADC_powerDown() function
void ADC_powerUp(ADC_Handle adcHandle)
{
ADC_Obj *adc = (ADC_Obj *)adcHandle;
ENABLE_PROTECTED_REGISTER_WRITE_MODE;
// set the bits
adc->ADCCTL1 |= ADC_ADCCTL1_ADCPWDN_BITS;
DISABLE_PROTECTED_REGISTER_WRITE_MODE;
return;
} // end of ADC_powerUp() function
```
利用bitwise的or(|=)或and(&=)進行暫存器的設定與清除。
bit反轉
bit mask
用來避免overflow
以TI INSTASPIN為例,angleMask避免角度超過 2^24 - 1
```cpp
//! \brief The angleDelayComp function compensates for the delay introduced
//! \brief from the time when the system inputs are sampled to when the PWM
//! \brief voltages are applied to the motor windings.
_iq angleDelayComp(const _iq fm_pu,const _iq angleUncomp_pu)
{
_iq angleDelta_pu = _IQmpy(fm_pu,_IQ(USER_IQ_FULL_SCALE_FREQ_Hz
/ (USER_PWM_FREQ_kHz*1000.0)));
_iq angleCompFactor = _IQ(1.0 + (float_t)USER_NUM_PWM_TICKS_PER_ISR_TICK
* 0.5);
_iq angleDeltaComp_pu = _IQmpy(angleDelta_pu,angleCompFactor);
uint32_t angleMask = ((uint32_t)0xFFFFFFFF >> (32 - GLOBAL_Q));
_iq angleComp_pu;
_iq angleTmp_pu;
// increment the angle
angleTmp_pu = angleUncomp_pu + angleDeltaComp_pu;
// mask the angle for wrap around
// note: must account for the sign of the angle
angleComp_pu = _IQabs(angleTmp_pu) & angleMask;
// account for sign
if(angleTmp_pu < _IQ(0.0))
{
angleComp_pu = -angleComp_pu;
}
return(angleComp_pu);
} // end of angleDelayComp() function
```
## Marco vs inline
基本上macro和inline function都可以省下速度,但Macro在預處理時,直接單純的文字替換,但inline function是在compile階段時,直接取代function。


`macro 因為是文字替換,所以若沒使用好運算子的優先順序,或是做太重複性的工作,便可能造成結果錯誤、效率不好等問題`
`inline 的使用要注意函式的長短,因為編譯器會考量有沒有合乎效益,來決定要不要將 function 展開為 inline,不然就只是一般 function`
## Typedef and handle
:dart: handle
In C language, a handle usually refers to a pointer that represents a resource or object allocated in memory. ==A handle is used to reference the resource or object without exposing its underlying implementation details==.
>from CHATGPT
可以對應O.O.P.技巧中的封裝。
```clike=
// the typedefs
//! \brief Defines the PID controller object
//!
typedef struct _PID_Obj_
{
_iq Kp; //!< the proportional gain for the PID controller
_iq Ki; //!< the integral gain for the PID controller
_iq Kd; //!< the derivative gain for the PID controller
_iq Ui; //!< the integrator start value for the PID controller
_iq refValue; //!< the reference input value
_iq fbackValue; //!< the feedback input value
_iq outMin; //!< the minimum output value allowed for the PID controller
_iq outMax; //!< the maximum output value allowed for the PID controller
} PID_Obj;
//! \brief Defines the PID handle
//!
typedef struct _PID_Obj_ *PID_Handle;
PID_Handle PID_init(void *pMemory,const size_t numBytes)
{
PID_Handle handle;
if(numBytes < sizeof(PID_Obj))
return((PID_Handle)NULL);
// assign the handle
handle = (PID_Handle)pMemory;
// set some defaults
PID_setUi(handle,_IQ(0.0));
PID_setRefValue(handle,_IQ(0.0));
PID_setFbackValue(handle,_IQ(0.0));
return(handle);
} // end of PID_init() function
int main()
{
PID_Obj pid_Tob; //pid struct
PID_Handle pidHandle_Tob; // pid struct的指標
pidHandle_Tob = PID_init(&pid_Tob,sizeof(pid_Tob)); //以這種方式初始化指標所指向的內容
}
```
這邊的初始化均為stack的初始化,一般的mcu中沒有記憶體管理單元,正常情況下不會有malloc()產生heap的操作。
为什么在单片机上的程序不怎么使用malloc,而PC上经常使用?因为单片机上没有已经写好的内存管理算法的代码,而在PC上操作系统里运行的程序,libc已经把这些都做了,只需要调用就可以了。如果在单片机上想用动态内存,也可以,但是这些代码要自己去实现,并定义一个相应的malloc,有时候一些公司会给提供一些库函数可能会实现malloc,但是因为单片机上RAM内存十分有限,如果不知道它的运行方式,估计会很危险。同样,因为在PC的系统上运行的程序与裸机程序不同,裸机程序不会有动态链接,有的只是静态链接。
:dart: [为什么在单片机上的程序不怎么使用malloc,而PC上经常使用?](https://mcu.eetrend.com/content/2020/100058605.html)
:pushpin: **why we don't use malloc() fun in mcu or dsp?**
In some cases, it may be possible or even necessary to use malloc() in a microcontroller or DSP application. However, there are several reasons why malloc() may not be the best choice for memory allocation in these systems:
1. Limited memory resources: Microcontrollers and DSPs typically have limited memory resources, and malloc() can be inefficient in terms of memory usage. malloc() requires additional memory for bookkeeping and managing the memory block, which can be a significant overhead in systems with limited memory resources.
1. Non-deterministic behavior: malloc() can have non-deterministic behavior, which means that the time it takes to allocate memory can vary depending on the current state of the heap. This can lead to unpredictable performance and response times, which can be problematic in real-time systems.
1. Memory fragmentation: Repeated calls to malloc() and free() can cause memory fragmentation, which means that the heap becomes fragmented with small blocks of free memory that cannot be used for larger allocations. This can lead to inefficient use of memory and can cause malloc() to fail even if there is enough total memory available.
1. Interrupt safety: In a system with interrupts, it is important to ensure that memory allocation and deallocation functions are interrupt-safe. malloc() is not interrupt-safe by default and may need to be modified or used with special care to ensure interrupt safety.
For these reasons, many microcontroller and DSP applications use static memory allocation or memory pools instead of malloc(). Static memory allocation allocates memory at compile time, while memory pools allocate a fixed amount of memory at initialization and manage the memory blocks using custom algorithms that are optimized for the specific application's memory usage patterns. These approaches can provide more predictable behavior and better memory usage in systems with limited memory resources and real-time requirements.
>from CHATGPT
:pushpin:typedefine常見陷阱
即它实际上相当于“char\*const”,而不是“const char\*(指向常量 char 的指针)
```cpp
typedef char* PCHAR;
int strcmp(const PCHAR,const PCHAR);
```
论什么时候,只要为指针声明 typedef,那么就应该在最终的 typedef 名称中加一个 const,以使得该指针本身是常量
```cpp
typedef const char* PCHAR;
int strcmp(PCHAR, PCHAR);
```
## HAL and handle
BSP VS HAL
BSP (board support package) consists of a set of drivers for predefined development board. HAL is an abstraction layer, as name says, and it serves as a layer between drivers and application, so application developer would not need to dig into hardware level and understand all the tiny details. Drivers are pieces of code that ideally know every tiny detail about the hardware they work with. So basically, application uses HAL, HAL checks what’s supported with current board from BSP and BSP provides a limited set of drivers. Since HAL is an abstraction, it may have many checks and other processing to make it universal. So when you need performance, you bypass HAL and talk directly to drivers at the price, you need to know many details about hardware and your code will be mostly limited to certain modes.
In other words,the BSP is a component that fits in with the HAL to provide support for a specific board. For example if you have library functions for a SPI interface you don’t want the application developer to have to worry about the details of which pins on the MCU are being used for SPI, which could differ from one design to another if an MCU supports pin remapping. The BSP typically takes care of setting up low level configuration like clock trees, pin assignments, the core clock, etc.
These APIs are the ones that configure a device peripheral, or a set of peripherals. Some of these functions are translated into a single function call to a peripheral configuration API, although they are still needed to allow the portability of the software architecture to work. An example of the simplest peripheral configuration is:
```cpp
// enable global interrupts
HAL_enableGlobalInts(halHandle);
```
Which is implemented as follows:
```cpp
void HAL_enableGlobalInts(HAL_Handle handle)
{
HAL_Obj *obj = (HAL_Obj *)handle;
CPU_enableGlobalInts(obj->cpuHandle);
return;
} // end of HAL_enableGlobalInts() function
```
==As can be seen, from the top level, a HAL function is called. In the HAL module itself, a CPU bit is changed. This HAL function might seem unnecessary, but it is actually needed to allow the top level to be fully portable to other MCUs or boards, which might modify another bit or bits to enable global interrupts(CPU_enableGlobalInts可以被替換掉,以方便toplevel的foc算法程式能夠被移植).==
## 函數POINTER
```cpp
#include <stdio.h>
#include <stdlib.h>
//int* (*a[5])(int,char*);
typedef int (*f)(int,char*);
f funp;
int foo(int n, char *s)
{
return 10086;
}
int main(int argc, char *argv[])
{
funp = &foo;
printf("%x\n",funp);
printf("%d\n",(*funp)(6,"test"));
return 0;
}
```
## CSM
code security module
## #pragma CODE\_SECTION(func1, "Sec1") ➝Flash功能
means: "func1 should be in program memory, in the memory area called Sec1". Sec1 will be a read-only memory location where the actual code of func1 will be allocated.
## #pragma DATA\_SECTION(globalvar1, "Sec2")
means: "globalvar1 should be in data memory, in the memory area called Sec2". Sec2 will be a read/write location where the variable globalvar1 will be allocated.
## const用法總整理
可以修飾函式的輸入引數,保護其在所定義的函式中不被修改(只能接受外面傳入)
輸出引數則不需要const如果const會失去輸出功能
針對指標的修飾 (qualifier)
指標本身不可變更 (Constant pointer to variable): const 在 * 之後
char * const pContent;
指標所指向的內容不可變更 (Pointer to constant): const 在 * 之前
const char * pContent;
char const * pContent;
兩者都不可變更
const char * const pContent;
## volatile變數
通知compiler這個變數常常更動,不要對其進行最佳化。
由於嵌入式系統常處理I/O、中斷、即時操作系統(RTOS)相關的問題,因此在嵌入式系統開發中 volatile 尤為重要。
被 volatile 修飾的變數代表它可能會被不預期的更新,因此==告知編譯器不對它涉及的地方做最佳化==,並在每次操作它的時候都讀取該變數實體位址上最新的值,==而不是讀取暫存器的值==。
* **volatile 常見的應用:**
* 修飾中斷處理程式中(ISR)中可能被修改的全域變數。
* 修飾多執行緒(multi-threaded)的全域變數。
* 設備的硬體暫存器(如狀態暫存器)
:dart: volatile
1. 被 volatile 宣告的變數 將不會使用最佳化編譯
有時一個變數的值改變了 compiler 並不會馬上將他寫入記憶體中
而會先把結果放在CPU暫存器中 等到處理結束之後 才寫入記憶體
若說這個變數是多執行緒的flag 其他的執行緒要透過這個變數來反應
而這個值卻又沒有寫入記憶體 這時便會發生意想不到的結果
2. 又或者是這變數為一個硬體的暫存器 會被硬體所改變
然而compiler 並沒有正確的將值從硬體暫存器取出來
而是將自己暫存的值拿來使用這種情況就是要用volatile來宣告變數告訴compiler不要自己暫存變數來提升速度如此這個變數有任何的改變便會馬上反應出來
## static inline function
一般我們在規範函數不讓其它文件訪問時會使用 static,但是只要透過指標就可以取得該函數並執行
inline function可建議compiler嵌入函式,能節省function呼叫的時間,但若函式包含遞迴或是內容龐大,則compiler會忽略inline請求。
以TI instaspin為例 所有pid控制器均修飾成static inline fun
一般在使用時須注意
1. 要被inline 的函式必須放在header file
1. 函式必須前面要是static inline ,而非單獨使用 inline
為什麼有 static 關鍵字的函式 foo() 可以正常被呼叫呢?
在某些資料中所說的「static 的可視範圍只在自己這個source file裡面」是一種簡化,且不完全正確的說法。正確的說法是「static 的可視範圍只在自己這個 translation unit 裡面」
所謂 translation unit 定義是:「某一個 source file (.c) 和所有這個 source file 引用的 header file (.h)」,而上述要將 source code 轉變成 translation unit 這件事是 preprocessor 的任務,接著會將translation unit丟給compiler。
所以使用static的函數若是放在headerfile中,仍然可以正常調用,而inline function要放在headerfile裡的原因也得到了答案,因為同一個 translation unit 並沒有包含實作函式庫 (.h)的 source file (.c),如果寫在 source file 裡面的話,preprocess 之後的 translation unit 就不會包含到該函式的實作,也就會造成 Error: undefined reference to 'xxx'。
GNU 會假定沒有加 static 的 inline function 會被其他 translation unit 所使用,因此 inline 是一定不會成功被整合(展開)到這個 inline function 所被呼叫到的地方了,因為如果真的inline到該地方有可能會導致其他translation unit無法使用,而且沒有加 static 的 inline function一定會被正常的把整個函式進行編譯。既然都會被編譯了,那麼在記憶體中所會佔的空間自然而然地就會比較大,而且也需要消耗呼叫函式的時間了。
:dart: In C and C++ programming language terminology, a **translation unit** (or more casually a compilation unit) is the ultimate input to a C or C++ compiler from which an object file is generated.[1] A translation unit roughly consists of a source file after it has been processed by the C preprocessor, meaning that header files listed in #include directives are literally included, sections of code within #ifndef may be included, and macros have been expanded.
## struct
```cpp
struct Employee{
char name[30]; // 名字
int age; //年齡
char gender; // 性別,'M' or 'F'
double salary; // 薪水
};
void initEmployee(struct Employee*,char[],int,char,double);
void initEmployee(struct Employee *employee,char name[],int age,char gender,double salary)
{
strcpy(employee->name, name);
employee->age = age;
employee->gender = gender;
employee->salary = salary;
}
指標型態Employee可用來存取Struct Employee的陣列。/
```
## Struct union
```plain
union Sample{
intindex;
doubleprice;
};
若 Sample ss; ss.index=10;//從今往後只能使用ss.index
若 Sample ss; ss.price=14.25;//從今往後只能使用ss.price
在union的使用中,如果給其中某個成員賦值,然後使用另一個成員,是未定義行為
struct Example
{
int index;
double price;
};
Example結構包含兩個成員,修改index不會對price產生影響,反之亦然。
union的成員共享內存空間,一個union只包含其中某一個成員。
說到這裡,大家應該已經明白兩者最關鍵的區別了吧,無非就在於內存單元的分配和使用。然而要靈活地使用struct和union 還是存在許多小技巧的,比如:元素的相關性不強時,完全是可以使用union,從而節省內存size; struct和union還可以相互嵌套。
```
extern static
## MCU硬體debounce
將按鈕並聯電容,透過充放電時間來度過按鈕機械抖動的狀態。

MCU中的低速CLOCK
1.watchdog(看門狗)2.Real-time clock(實時時鐘),簡單說明
1.看門口主要功能是檢測程式運行時有沒有異常的執行時間,有的話可以讓MCU自動重製。
2.實時時鐘則是計數時間32.768kHz為計數1秒最精準的頻率。
補充FPGA debounce電路設計~
GPIO的八種模式
1.開漏輸出 (Output open-drain)
2.推輓輸出 (Output push-pull)
3.複用開漏輸出(Alternate function open-drain)
4.複用推輓輸出(Alternate function push-pull)
5.類比輸入 (Input Analog)
6.浮空輸入 (Input floating)
7.下拉輸入 (Input pull-down)
8.上拉輸入 (Input pull-up)

## rpi3 驅動程式

當你要驅動一個硬體,無論是簡單的還是複雜的,必須要考慮:
* 使用者要如何去呼叫這個硬體,以便讓系統許可使用(system call, ioctl)
* 系統要怎麼初始硬體(module_init)
* 系統要怎麼脫離硬體(module_exit)
* 系統跟硬體的互動(interrupt, irq)
* 硬體跟使用者的互動(open, close, read, write, ioctl, copy_from_user, copy_to_user)
* 要如何解析硬體傳來的訊號(keyword : 傳輸協定,SPI, I2C, ...)
* 跟別的module的相依性
* 是否容許多人同時使用?如何分配資源?
以下是我自己考慮的部份:
盡可能用kernel已經有的支援以減少coding
盡可能考慮與不同系統搭配的可能性(如果你想把raspberry pi的驅動程式移植到BeagleBone Black上....)。
當使用者想要使用某個硬體時,必須要這樣做(以下為擬人化示範):
使用者:喂!那個webcam可不可以給我用一下?就是在/dev/video0的那個!(以開啟/dev/video0的方式去呼叫系統,所謂system call是也) 系 統:我先看一下你夠不夠格用(使用者是否有權限),然後我看有沒有別人在用(mutex)....嗯,應該可以讓你用,我先把設定開一開 (interrupt與irq等),這樣我想應該沒問題了,拿去用吧(使用者以mutex lock(互斥鎖)佔住/dev/video0),然後系統開始根據使用者的要求傳送畫面.... 使用者:喂!我用完了,我把webcam放在那囉,你自己收一收吧(以關閉/dev/video0的方式通知系統) 系統:把設定(interrupt與irq等)關掉,互斥鎖也解掉,這樣別人就能用了。
當使用者要使用系統的一個裝置(device),系統必須有一個相應的字符裝置驅動程式(character device driver),而這個character device driver 會在虛擬檔案系統(virtual file system)創造一個字符裝置檔案(character device file)如下圖,例如本文的/dev/video0或我們下一篇會建立的/dev/LED_0,使用者就能透過開啟此虛擬檔案的方式,告訴系統他想要這裝製作什麼,系統再依照字符裝置驅動程式的設定決定要怎麼回應。

## debug介面介紹
* JTAG and Real time JTAG
Real-time JTAG (Joint Test Action Group) is a feature that allows for debugging and testing of a digital circuit while it is still running. This means that modifications can be made to the circuit's behavior in real-time, without needing to halt or reset the system.
In the context of the statement mentioned earlier, the devices in the 28x family have a unique hardware implementation of real-time mode within the CPU, which allows for modifications to memory, peripheral, and register locations while the processor is running and executing code. This is different from traditional JTAG debugging, which requires the circuit to be paused or halted before modifications can be made.
Real-time JTAG is a powerful feature that can greatly enhance the debugging and testing of complex digital circuits. It allows for faster development cycles and more efficient debugging, as issues can be identified and resolved in real-time.
:dart: what is the relationship between JTAG and stlink circuit?
ST-Link is a hardware and software debugging toolset for STM32 microcontrollers, which provides JTAG/SWD interfaces for debugging and programming the microcontrollers. In other words, ST-Link is a hardware platform that includes JTAG functionality as part of its features.
JTAG is a standard interface for testing and debugging digital circuits that use boundary scan architecture, while ST-Link is a specific hardware toolset that uses JTAG interfaces for debugging STM32 microcontrollers. The ST-Link hardware provides a JTAG interface, which allows developers to perform boundary scan testing, device programming, and in-system debugging of the STM32 microcontrollers.
In summary, ST-Link is a hardware and software toolset that uses JTAG interfaces to provide debugging and programming capabilities for STM32 microcontrollers. While JTAG is a standard interface used for testing and debugging a wide range of digital circuits, including the STM32 microcontrollers that ST-Link is designed to work with.
* SWD
SWD (Serial Wire Debug) is a debug interface similar to JTAG, used for in-system programming and debugging of microcontrollers. It is a two-wire interface, consisting of a clock signal (SWCLK) and a bidirectional data signal (SWDIO), which reduces the pin count required compared to JTAG.
SWD was developed by ARM and is used in many of their microcontrollers, including Cortex-M series processors. SWD is generally faster than JTAG and uses fewer pins, making it a more attractive option for debugging and programming microcontrollers in systems with limited pin counts.
Like JTAG, SWD allows for debugging and programming of microcontrollers while they are in operation. It can be used with specialized software tools, such as Integrated Development Environments (IDEs) and debuggers, to allow developers to inspect and modify the internal state of a microcontroller in real-time.
JTAG/SWD/SWIM ->一種debug的軟體介面
STLINK/XDS100/JLINK ->硬體介面其中包含debug軟體介面(JTAG/SWD)