Site icon TAPIT

RAM MEMORY: Cấu trúc, chức năng và thực hành debug trên VĐK STM32 (Phần 1)

Tại sao cần nắm vững kiến thức về RAM?

Trong lĩnh vực Lập trình nhúng, đặc biệt đối với các hệ thống sử dụng Vi điều khiển, việc quản lý và sử dụng hiệu quả tài nguyên bộ nhớ là một vấn đề mà người lập trình cần quan tâm. Việc hiểu về cấu trúc và cơ chế hoạt động của bộ nhớ RAM sẽ giúp cho chúng ta:

Chuỗi bài viết này sẽ cùng bạn khám phá bộ nhớ RAM từ cấu trúc, chức năng, nguyên lý hoạt động đến các kỹ thuật thực hành và gỡ lỗi trên nền tảng vi điều khiển STM32.

–o–

Phần 1. Tổng quan về RAM. Cấu trúc và chức năng của phân vùng Data và BSS

 

1. Ý nghĩa của từ khoá “RAM”

RAM – Random-access memory (Bộ nhớ truy cập ngẫu nhiên). Dựa theo tên đầy đủ của RAM, chúng ta sẽ phân tích với 2 đặc tính “access” và “random”:

2. Phân loại RAM

Bộ nhớ RAM bao gồm 2 loại kiến trúc cơ bản: DRAM (Dynamic RAM – RAM động) và SRAM (Static RAM – RAM tĩnh). Sự khác nhau giữa 2 kiến trúc này nằm ở cấu trúc tế bào bộ nhớ (memory cell) và cơ chế duy trì dữ liệu.

Điểm chung của DRAM và SRAM là đều phụ thuộc vào nguồn điện cung cấp thì mới duy trì được dữ liệu trên bộ nhớ. Toàn bộ dữ liệu lưu trữ trong RAM sẽ mất khi nguồn cung cấp bị ngắt. Đó chính là đặc điểm của Volatile memory.

3. Đặc tính của RAM

Một số đặc tính của RAM:

Với những đặc tính trên, RAM đóng vai trò là nơi lưu trữ dữ liệu tạm thời trong quá trình chương trình thực thi.

Tiếp theo, chúng ta cùng tìm hiểu về cơ chế lưu trữ dữ liệu trên kiến trúc bộ nhớ RAM.

4. Kiến trúc chung của RAM

Bộ nhớ RAM bao gồm 4 phân vùng cơ bản (phân bổ từ địa chỉ thấp lên cao): Data, BSS, Heap, Stack. 

Hình 1. Cấu trúc các phân vùng của bộ nhớ RAM

4.1. Phân vùng Initialized Data (Data) – Phân vùng dữ liệu khởi tạo 

Trước khi đi vào các ví dụ cụ thể, chúng ta sẽ cùng nhau thiết lập môi trường phát triển để hỗ trợ quá trình gỡ lỗi (debug).

+ Công cụ: Chúng ta sẽ sử dụng STM32CubeIDE để biên dịch các chương trình ví dụ. Để thực hành, bạn đọc cần chuẩn bị một kit phát triển STM32. Trong chuỗi bài viết này, mình sẽ sử dụng kit STM32F103C6T6. Tuy nhiên, bạn hoàn toàn có thể sử dụng bất kỳ kit STM32 nào khác, vì quy trình triển khai là tương tự.

+ File map: Trong thư mục Debug sẽ sinh ra file map – file cung cấp chi tiết về dữ liệu của chương trình được sắp xếp trong bộ nhớ (Flash và RAM) của vi điều khiển.

Hình 2. Vị trí file map (*.map) trong cây thư mục dự án

+ Cửa sổ Memory: công cụ gỡ lỗi vô cùng quan trọng, cho phép bạn quan sát trực tiếp nội dung của bộ nhớ (RAM và Flash) của vi điều khiển STM32 trong quá trình debug. 

Hình 3. Các bước để truy cập cửa sổ Memory trong debug

Ví dụ 1: Chương trình với biến toàn cục và biến static mang giá trị khởi tạo khác 0.

Phân tích file map, chúng ta biết được địa chỉ bắt đầu của phân vùng data và địa chỉ lưu trữ giá trị cho các biến toàn cục và biến static được khai báo trong chương trình.

Hình 4. Địa chỉ và kích thước của biến toàn cục và biến static trong phân vùng Data tại file map 

Sau khi biết được địa chỉ bắt đầu của phân vùng Data (0x20000000) và địa chỉ lưu trữ giá trị các biến, mình tiếp tục Debug và kiểm tra các giá trị được lưu trữ tại cửa sổ Memory của STM32 CubeIDE.

Hình 5. Debug giá trị khởi tạo và giá trị sau hiệu chỉnh của các biến tại phân vùng Data

Ví dụ 2: Chương trình với biến chuỗi chứa dữ liệu string literal

Hình 6. Địa chỉ và kích thước của các biến trong phân vùng Data tại file map

Biến toàn cục month2rd và biến static tapitslogan sẽ được lưu trữ tại phân vùng Data. Điểm khác biệt ở đây là các giá trị literal. Giá trị literal sẽ được phân bổ tại phân vùng Read Only Data (rodata) thuộc bộ nhớ ROM. 

Biến con trỏ tapitslogan lưu trữ địa chỉ bắt đầu của chuỗi literal “Learning-Research-Sharing” là 0x08001210.

Hình 7. Debug dữ liệu biến tại phân vùng ROData (ROM) và Data (RAM)

4.2. Phân vùng Uninitialized Data (BSS) – Phân vùng dữ liệu không khởi tạo

Ví dụ 3: Chương trình với biến toàn cục và biến static mang giá trị khởi tạo bằng 0.

Dựa vào file map, chúng ta biết được địa chỉ bắt đầu của phân vùng BSS (0x20000060) và địa chỉ lưu trữ giá trị cho các biến toàn cục và biến static được khởi tạo bằng 0.

Hình 8. Địa chỉ và kích thước của các biến trong phân vùng BSS tại file map

Hình 9. Debug giá trị khởi tạo và giá trị sau hiệu chỉnh của các biến tại phân vùng BSS

Qua các chương trình ví dụ, chúng ta đã tiến hành phân tích chi tiết địa chỉ của các biến trong các phân vùng bộ nhớ. Đồng thời, việc debug đã giúp chúng ta quan sát giá trị khởi tạo và sự cập nhật giá trị của từng biến. Để hiểu rõ hơn cách dữ liệu được lưu trữ trên các phân vùng Data và BSS, bạn nên thực hành viết các chương trình đơn giản và thực hiện gỡ lỗi.

Qua bài viết này, mình hy vọng mang đến cái nhìn tổng quan về cấu trúc bộ nhớ RAM; cũng như làm rõ đặc điểm chức năng và hoạt động của hai phân vùng Data và BSS.

Cùng đón chờ phần 2 của chuỗi bài viết này nhé, chúng ta sẽ tiếp tục phân tích hai phân vùng còn lại là Heap và Stack. Đây là hai phân vùng quan trọng có ảnh hưởng trực tiếp đến hiệu suất và tính ổn định của chương trình.

Chúc các bạn thành công!

N.T.Nhien

Tìm hiểu thêm:
Tổng hợp hướng dẫn Internet of Things với NodeMCU ESP8266 và ESP32
Tổng hợp các bài hướng dẫn Lập trình vi điều khiển STM32
[HỌC ONLINE: LẬP TRÌNH VI ĐIỀU KHIỂN STM32, VI XỬ LÝ ARM CORTEX – M]
Fanpage TAPIT: TAPIT – AIoT Learning