Saturday, November 8, 2025

FLASH - CLOCK - ART

Trong quá trình giảng dạy về Embedded firmware, tôi gặp bài toán tăng perfomance bằng cách tăng tốc độ xử lý của CPU. Tôi gặp vấn đề về CPU chạy nhanh hơn flash

  • Code đưc lưu ở flash

A white rectangular table with black text

AI-generated content may be incorrect.

--> Trong datasheet của STM32F411, ta thấy rằng tốc độ flash phụ thục vào điện áp hoạt động. Tôi sử dụng 3.0 Vol --> Tốc độ flash tối đa là 30MHz

  • Code sẽ đưc thực thi trên CPU --> Trong khi đó tốc độ CPU đưc config tối đa lên đến 100Mhz

--> Vấn đề ở đây là CPU đọc code ở flash lên chậm quá so với việc thực hiện code --> hiện tưng: làm treo chương trình

--> Giải quyết vấn đề: chúng ta cần config cho CPU để chờ thêm 3WS (wait states) để KỊP đọc code từ FLASH lên

--> Tiếp tục phát sinh vấn đề nữa: Set tốc độ nhanh làm gì mà phải chờ 3WS làm giảm performance

--> Giải pháp: Trong STM32F411 cung cấp ART Accelerator (Adaptive Real-Time)

ART Accelerator: Nó là phần cứng nằm giữa FLASH và CPU. Nhiệm vụ của nó để tăng performance để giảm wait states (WS)

Text Box: Nếu sử dụng ART ta thấy: 
•	Lần đâu đọc CODE từ FLASH lên CPU để thực E (execute - thực hiện) thì nó cần 4 cpu cycles bao gồm 1F (fetch) + 3WS
•	Trong lúc thực hiện CODE, thì bộ ART nó sẽ đọc CODE từ FLASH lên CPU. Nên mình thấy nó thực hiện CODE liên tục. Nên dường như không cần thêm WS nữa

Text Box: Nếu không sử dụng ART ta thấy: 
•	Một lần CPU đọc data từ FLASH lên thì nó cần 4 cpu cycles (4 xung clock) bao gồm 1F (fetch) + 3WS (wait states) - Do flash của STM32 là 128-bits (với 1 câu lệnh - instruction) là 32 bit (STM32F411 sử dụng kiến trúc 32bits) do đó một lần đọc code từ FLASH nó đọc 4 instruction
•	Ở lần tiếp theo nó cũng cần 4 cpu cycles bao gồm 1F + 3WS
A diagram of a staircase

AI-generated content may be incorrect.

Nếu chúng ta sử dụng ART

A diagram of a diagram

AI-generated content may be incorrect.

 

 

 

-------------------------------------

Ngoài ra, nếu MCU không support ART thì những đoạn code nào cần thực thi nhanh. thì chúng ta đưa hàm đó lên RAM. Vì tốc độ đọc dữ liệu từ RAM sẽ nhanh hơn FLASH rất nhiều

__attribute__((section(".ham_tren_ram"))) void update()

{

        __asm("CPSID i");

    flash_erase(0);

    for(int i = 0; i < RX_BUFFER_SIZE; i++)

    {

            flash_program((char*)0x08000000 + i, rx_buffer[i]);

    }

    uint32_t* AIRCR = (uint32_t*)0xE000ED0C;

    *AIRCR = (0x5FA << 16) | (1 << 2);

}

 

Sunday, July 20, 2025

Makefile

 

1. Makefile là gì?

⦁ Makefile là file cấu hình được dùng bởi lệnh make, giúp tự động hóa quá trình biên dịch mã nguồn.

2. Cấu trúc cơ bản của một Makefile

target: dependencies
<TAB>command

Lưu ý: Dòng lệnh sau target phải bắt đầu bằng một tab (không phải dấu cách!).

3. Ví dụ đơn giản

program: lib1.c lib2.c main.c
    gcc -c main.c -o main.o
    gcc -c lib1.c -o lib1.o
    gcc -c lib2.c -o lib2.o
    gcc lib1.o lib2.o main.o -o program
  • Makefile này sẽ hoạt động như sao:
    • targer là program
    • dependencies: lib1.c lib2.c main.c

--> Có nghĩa là:

  • Để build được target (program) thì chúng ta cần những dependency kia
  • Khi một trong những file trong dependencies thay đổi nội dung thì target sẽ đc chạy

4. Tự động hóa với makefile

4.1. Khi chúng ta chỉ thay đổi main.c, trigger build thì nó sẽ build lại file main.c và cả 2 file lib gây tốn thời gian do đó chúng ta tách ra như thế này:

program: lib1.o lib2.o main.o
    gcc lib1.o lib2.o main.o -o program

lib1.o: lib1.c
    gcc -c lib1.c -o lib1.o

lib2.o: lib2.o
    gcc -c lib2.c -o lib2.o

main.0: main.c
    gcc -c main.c -o main.o
  • lúc này program sẽ dependency lib1.o lib2.o main.o (chứ không phải các file .c)
  • mỗi file .o sẽ được tạo ra từ các file .c --> khi thôi đổi file.c nào thì file.o sẽ được build lại, chứ không phải build lại tất cả --> chúng ta sẽ tiết kiệm được khá nhiều thòi gian

4.2. Makefile ở trên cũng còn nhược điểm, trong project của chúng ta chỉ có 3 file .c thôi, thì cũng ta viết nổi, chứ project có 10000 file.c là không viết nổi luôn

program: lib1.o lib2.o main.o
 	gcc lib1.o lib2.o main.o -o program

%.o: %.c
    gcc -c $^ -o $@
  • $^ : là danh sách dependencies
  • $@ : là targer

4.3. Chúng ta có thể print log để debug trong Makefile

program: lib1.o lib2.o main.o
 	gcc lib1.o lib2.o main.o -o program

%.o: %.c
    $(info Dang build @^ thanh $@)
 	gcc -c $^ -o $@
  • sử dụng $(info ...) để in information (ngoài ra chúng ta có thể sử dụng error, debug...)

4.4. Trong dependencies của program vẫn chưa tối ưu

SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)
program: $(OBJS)
 	gcc $(OBJS) -o $@

%.o: %.c
    $(info Dang build $^ thanh $@)
 	gcc -c $^ -o $@
debug:
    $(info sources: $(SRCS))
    $(info objects: $(OBJS))
  • $(wildcard *.c) tìm tất cả các file .c trong thư mục hiện tại.
  • Gán danh sách đó cho biến SRCS.
  • $(SRCS:.c=.o) chuyễn lib1.c lib2.c main.c thành lib1.o lib2.o main.o
D:\Temp_Dir\c_sample> make debug
sources: lib1.c lib2.c main.c
objects: lib1.o lib2.o main.o

4.5. Với makefile trên thì khi chúng ta thay đổi nội dung file.h thì nó không rebuild

CC=gcc
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)
FLAG=-MMD
program: $(OBJS)
	$(info link all object files to $@)
	$(CC) $(OBJS) -o $@
%.o: %.c
	$(info build $< to $@)
	$(CC) -c $(FLAG) $< -o $@
debug:
	$(info sources: $(SRCS))
	$(info objects: $(OBJS))

clear: 
	rm *.o *.exe
-include *.d
  • Sử dụng -MMD để gcc tạo ra những file.d trong file.d đó nó sẽ liệt kê các file cần thiết cho quá trình biên dịch của file đó. VD ta có một main.d
PS D:\Temp_Dir\c_sample> cat main.d
main.o: main.c lib2.h lib1.h

PS D:\Temp_Dir\c_sample> cat lib1.d
lib1.o: lib1.c
  • Trong main.c có #include "lib2.h" trong lib2.h của #include "lib1.h" do đó depedencies của main.o là main.clib2.h và lib1.h
  • Trong lib1.c không có include thư viện nào cả, nên nó chỉ có depedency một file `lib1.c' thôi
  • Cuối cùng là sử dụng -include *.d để thêm tất cả các file.d vào khi chạy make

Friday, January 10, 2025

 Nhân build YOCTO - Build SDK

1. Mục tiêu

- Bình thường chúng ta cần phải download source của kernal về và một số BSP để build OS. Thay vì vậy mình sử dụng yocto project để build SDK cho đồng bộ

2. Build SDK

vbuser@Ubuntu18:~/Desktop/selfstudy/poky/build$ bitbake core-image-minimal -c populate_sdk

Loading cache: 100% |#############################################################################################################################| Time: 0:00:00

Loaded 1306 entries from dependency cache.

NOTE: Resolving any missing task queue dependencies


Build Configuration:

BB_VERSION           = "1.44.0"

BUILD_SYS            = "x86_64-linux"

NATIVELSBSTRING      = "universal"

TARGET_SYS           = "i686-poky-linux"

MACHINE              = "qemux86"

DISTRO               = "poky"

DISTRO_VERSION       = "3.0.4"

TUNE_FEATURES        = "m32 core2"

TARGET_FPU           = ""

meta                 

meta-poky            

meta-yocto-bsp       

meta-skeleton        = "zeus:daf096e295121ea49ebf21f8070e9a6e28f5d46c"


Initialising tasks: 100% |########################################################################################################################| Time: 0:00:01

Sstate summary: Wanted 352 Found 0 Missed 352 Current 472 (0% match, 57% complete)

NOTE: Executing Tasks

NOTE: Setscene tasks completed

NOTE: Tasks Summary: Attempted 3058 tasks of which 2051 didn't need to be rerun and all succeeded.


3. Run SDK installer

- Đầu tiên chúng ta cần cài đặt SDK vào host (cái máy dùng để build kernel). Cái SDK installer này là mấy file .sh (shell script), nó sẽ được tìm thấy trong "build/tmp/deploy/sdk" ở đây mình sử dụng "core-image-minimal" nên mọi người có thể sử dụng "poky-glibc-x86_64-core-image-minimal-core2-32-qemux86-toolchain-3.0.4.sh" để cài đặt SDK.  


vbuser@Ubuntu18:~/Desktop/selfstudy/poky/build$ cd tmp/deploy/sdk

vbuser@Ubuntu18:~/Desktop/selfstudy/poky/build/tmp/deploy/sdk$ tree -L 1 .

.

├── poky-glibc-x86_64-core-image-minimal-core2-32-qemux86-toolchain-3.0.4.host.manifest

├── poky-glibc-x86_64-core-image-minimal-core2-32-qemux86-toolchain-3.0.4.sh

├── poky-glibc-x86_64-core-image-minimal-core2-32-qemux86-toolchain-3.0.4.target.manifest

└── poky-glibc-x86_64-core-image-minimal-core2-32-qemux86-toolchain-3.0.4.testdata.json


0 directories, 4 files



***Chú ý: SDK installer sẽ hỏi mọi nguời thư mục cài đặt SDK

vbuser@Ubuntu18:~/Desktop/selfstudy/poky/build/tmp/deploy/sdk$ ./poky-glibc-x86_64-core-image-minimal-core2-32-qemux86-toolchain-3.0.4.sh 

Poky (Yocto Project Reference Distro) SDK installer version 3.0.4

=================================================================

Enter target directory for SDK (default: /opt/poky/3.0.4): /home/vbuser/Desktop/selfstudy/SDK

You are about to install the SDK to "/home/vbuser/Desktop/selfstudy/SDK". Proceed [Y/n]? Y

Extracting SDK.............................................done

Setting it up...done

SDK has been successfully set up and is ready to be used.

Each time you wish to use the SDK in a new shell session, you need to source the environment setup script e.g.

 $ . /home/vbuser/Desktop/selfstudy/SDK/environment-setup-core2-32-poky-linux



4. Using the SDK

- Chúng ta có thể sử dụng cái SDK để dev application

4.1. Run SDK environment setup script

- Tạo một cái working directory để chứa một cái example app để sử dụng SDK.
- Sao đó chúng ta chúng ta chạy environment để sử dụng SDK, à chú ý: chúng ta đứng ở thư mục mới tạo và source environment trong thư mục SDK đã cài đặt

vbuser@Ubuntu18:~/Desktop/selfstudy$ mkdir App_Workspace

vbuser@Ubuntu18:~/Desktop/selfstudy$ cd App_Workspace/

vbuser@Ubuntu18:~/Desktop/selfstudy/App_Workspace$ source ../SDK/

environment-setup-core2-32-poky-linux  site-config-core2-32-poky-linux        sysroots/                              version-core2-32-poky-linux

vbuser@Ubuntu18:~/Desktop/selfstudy/App_Workspace$ source ../SDK/environment-setup-core2-32-poky-linux 


4.2. Bây giờ chúng ta tạo hello world bằng code C thôi


vbuser@Ubuntu18:~/Desktop/selfstudy/App_Workspace$ cat helloworld.c 

#include <stdio.h>



void main()

{

printf("Hello world \r\n");

}


vbuser@Ubuntu18:~/Desktop/selfstudy/App_Workspace$ cat Makefile 

all: helloworld

$(CC) helloworld.c -o helloworld

clean:

rm helloworld


vbuser@Ubuntu18:~/Desktop/selfstudy/App_Workspace$ make

i686-poky-linux-gcc  -m32 -march=core2 -mtune=core2 -msse3 -mfpmath=sse -fstack-protector-strong  -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/home/vbuser/Desktop/selfstudy/SDK/sysroots/core2-32-poky-linux  -O2 -pipe -g -feliminate-unused-debug-types   -Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed -fstack-protector-strong -Wl,-z,relro,-z,now  helloworld.c   -o helloworld

i686-poky-linux-gcc  -m32 -march=core2 -mtune=core2 -msse3 -mfpmath=sse -fstack-protector-strong  -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/home/vbuser/Desktop/selfstudy/SDK/sysroots/core2-32-poky-linux helloworld.c -o helloworld


--> Mọi người có thể thấy rằng, nó sử dụng i686-poky-linux-gcc (cái này là compiler của yocto build cho core-image-minimal) mọi người có thể copy vào máy ảo chạy ./helloworld để xem kết quả.