Khi học bất kì con vi điều khiển nào, đầu tiên chúng ta cần tìm hiểu cấu trúc và bản đồ bộ nhớ (memory map) của vi điều khiển đó. Điều này sẽ giúp chúng ta nắm rõ được cách thức nó hoạt động, chạy chương trình, chạy code như thế nào.
Bài viết nằm trong Serie Học STM32 từ A tới Z
Kiến trúc vi điều khiển STM32F103
Sơ đồ tổng quan
• 4 master (thiết bị chủ động truy cập bus):
– Cortex®-M3 core DCode bus (D-bus) và System bus (S-bus)
– GP-DMA1 & 2 (general-purpose DMA)
• 4 slave (thiết bị bị truy cập):
– Internal SRAM: RAM nội
– Internal Flash memory: bộ nhớ Flash nội
– FSMC: bộ điều khiển kết nối bộ nhớ ngoài
– AHB to APBx (APB1 hoặc APB2): cầu nối tới các ngoại vi APB

Dcode Bus
Kết nối bus DCode của lõi Cortex-M3 (dùng để đọc hằng số trong code và cho debugger truy cập) với giao diện dữ liệu của bộ nhớ Flash.
System Bus
Bus này kết nối bus hệ thống của lõi Cortex®-M3 (bus thiết bị ngoại vi) với BusMatrix, nơi phân xử việc truy cập giữa Core và DMA.
DMA bus
Bus này kết nối giao diện master AHB của DMA với BusMatrix. BusMatrix quản lý quyền truy cập của CPU DCode và DMA tới SRAM, bộ nhớ Flash và thiết bị ngoại vi.
BusMatrix
BusMatrix quản lý việc phân xử truy cập giữa bus hệ thống của lõi và bus master của DMA, sử dụng thuật toán Round Robin. Ở dòng Connectivity line (STM32F105/107), BusMatrix gồm năm master (CPU DCode, System bus, Ethernet DMA, DMA1 và DMA2) và ba slave (FLITF, SRAM và AHB2APB).
Ở các dòng khác (trong đó có STM32F103), BusMatrix gồm bốn master (CPU DCode, System bus, DMA1 và DMA2) và bốn slave (FLITF, SRAM, FSMC và AHB2APB). Các thiết bị ngoại vi AHB được kết nối trên bus hệ thống thông qua BusMatrix để DMA cũng có thể truy cập được.
AHB/APB bridges (APB)
Hai cầu AHB/APB cung cấp kết nối đồng bộ giữa AHB và 2 bus APB. APB1 được giới hạn ở 36 MHz, APB2 hoạt động ở tốc độ tối đa (lên đến 72 MHz tùy thuộc vào thiết bị).
Sau mỗi lần reset, clock của tất cả các ngoại vi đều bị tắt (ngoại trừ SRAM và FLITF). Trước khi sử dụng ngoại vi nào, bạn phải bật clock của nó trong thanh ghi RCC_AHBENR, RCC_APB2ENR hoặc RCC_APB1ENR.
Lưu ý: Đây là lỗi kinh điển khi lập trình thanh ghi: quên bật clock cho ngoại vi thì ghi gì vào thanh ghi của nó cũng không có tác dụng, đọc ra toàn 0. Khi dùng CubeMX/HAL thì các macro __HAL_RCC_xxx_CLK_ENABLE() đã được sinh sẵn trong hàm MspInit nên bạn ít gặp hơn.
Core registers ( Thanh ghi lõi)
R0 – R12 là các thanh ghi đa dụng (general purpose), có thể được sử dụng làm toán hạng cho các lệnh ARM.
Một số thanh ghi đa dụng có thể được trình biên dịch dùng vào các mục đích đặc biệt (ví dụ truyền tham số khi gọi hàm).
Thanh ghi R13 là Stack Pointer (SP), trỏ tới đỉnh của ngăn xếp (stack). Ngăn xếp hoạt động theo kiểu LIFO (Last In First Out): dữ liệu vào sau thì ra trước, giống như chồng đĩa, đĩa đặt lên cuối cùng sẽ được lấy ra đầu tiên. R14 là Link Register (LR) lưu địa chỉ trả về khi gọi hàm, R15 là Program Counter (PC) trỏ tới lệnh đang thực thi.

Bản đồ bộ nhớ STM32f103 (Memory Maps)
ARM quy định một không gian địa chỉ bộ nhớ chuẩn chung cho tất cả các lõi Cortex-M, nhờ vậy code dễ dàng chuyển giữa chip của các hãng khác nhau.
Bạn có thể hình dung memory map giống như bản đồ một thành phố: mỗi khu phố (vùng nhớ) có một dải số nhà (địa chỉ) riêng, muốn gửi thư cho ai (đọc ghi thanh ghi nào) thì chỉ cần biết đúng số nhà là tới nơi.
Không gian bộ nhớ (memory) được thiết kế chia thành một số vùng khác nhau: Code, SRAM, Peripherals, External RAM, External Device, Private Peripheral Bus internal và external, Vendor Specific như hình sau:

Code Area

512MB đầu tiên được dành riêng cho vùng code. Tất cả các bộ xử lý Cortex-M đều ánh xạ vùng code bắt đầu từ địa chỉ 0x0000 0000. Khu vực này cũng chứa giá trị khởi tạo của con trỏ ngăn xếp (thường trỏ vào SRAM) và bảng vector ngắt.
Trên thực tế, với tất cả các dòng STM32, vùng bắt đầu từ địa chỉ 0x0800 0000 là bộ nhớ Flash bên trong MCU, nơi chứa mã chương trình. Khi boot từ Flash (chân BOOT0 = 0), vùng này được ánh xạ thêm (alias) về địa chỉ 0x0000 0000.
Điều này có nghĩa là có thể đọc nội dung của bộ nhớ Flash ở cả địa chỉ 0x0800 0000 và địa chỉ 0x0000 0000.
Hai phần cuối dành riêng cho bộ nhớ hệ thống (System Memory) và Option Bytes.
System Memory – Bộ nhớ hệ thống
Bộ nhớ hệ thống là vùng ROM dành riêng cho bộ nạp khởi động (Boot Loader) do ST lập trình sẵn vào chip trong quá trình sản xuất. Tùy từng họ STM32, Boot Loader này có thể nạp code qua USART, USB, CAN…
Lưu ý: Với STM32F103 (KIT Blue Pill), Boot Loader gốc trong System Memory chỉ hỗ trợ nạp qua USART1 (PA9/PA10, đặt BOOT0 = 1). Dù chip có ngoại vi USB, bạn không thể cắm cáp USB vào là nạp code được như một số dòng STM32 khác, trừ khi tự nạp thêm 1 Boot Loader USB vào Flash.
Option Bytes – Vùng tùy chọn byte
Vùng Option Bytes chứa một loạt cờ bit dùng để cấu hình một số tính năng của MCU (như bảo vệ đọc ghi Flash, v.v.).
SRAM Area
Sram là gì?
SRAM là viết tắt của Static Random-Access Memory (bộ nhớ truy cập ngẫu nhiên tĩnh hay RAM tĩnh). SRAM giữ được dữ liệu miễn là còn được cấp nguồn. Không giống như DRAM lưu mỗi bit trong một tụ điện nhỏ, SRAM không cần phải làm tươi (refresh) theo định kỳ.
Sram trong STM32 tổ chức ra sao?
Vùng SRAM bắt đầu từ địa chỉ 0x2000 0000 và có thể kéo dài đến 0x3FFF FFFF. SRAM được sử dụng để lưu biến (data), heap và stack.
Tuy nhiên, địa chỉ kết thúc thực tế phụ thuộc vào dung lượng SRAM có trong chip. Ví dụ: STM32F103RB (hay STM32F103C8 trên KIT Blue Pill) có 20KB SRAM = 0x5000 byte, nên địa chỉ cuối cùng là 0x2000 4FFF. Cố gắng truy cập vào một vị trí bên ngoài khu vực này sẽ gây ra lỗi Bus Fault (thường thấy dưới dạng HardFault).
Trong vùng nhớ này, 1MB đầu tiên là vùng Bit-band. Mỗi bit trong vùng Bit-band được ánh xạ sang 1 word riêng ở vùng alias (bắt đầu từ 0x2200 0000), nhờ đó có thể đọc/ghi từng bit độc lập mà không cần đọc – sửa – ghi cả byte. Bạn cũng có thể thực thi code từ vùng nhớ SRAM, vi xử lý không cấm việc chạy chương trình từ đây.
Peripheral Area
Mọi thiết bị ngoại vi của MCU (Timer, I2C, SPI, USART, v.v.) đều được ánh xạ vào vùng này (từ 0x4000 0000). Chi tiết địa chỉ các thanh ghi ngoại vi phụ thuộc vào từng dòng vi điều khiển, các bạn nên đọc Reference Manual của từng loại để hiểu rõ hơn.
External RAM Area
Nếu bộ nhớ RAM tích hợp sẵn trên vi điều khiển không đủ và bạn muốn kết nối với 1 bộ nhớ RAM ngoài thì bạn có thể khai thác chức năng của vùng nhớ này.
Các thiết bị Cortex-M có thể thực thi mã và đọc/ghi dữ liệu từ các bộ nhớ ngoài, giúp mở rộng tài nguyên bộ nhớ trong, thông qua giao diện EMI/FSMC. Lưu ý FSMC chỉ có trên các dòng STM32F103 high-density (như STM32F103ZE), con STM32F103C8 trên Blue Pill không có FSMC.
Kết
Nắm rõ cấu trúc và bộ nhớ (memory) của stm32 sẽ giúp ích rất nhiều trong việc hiểu sâu về vi điều khiển, từ đó trở thành một lập trình viên ưu tú hơn. Nên nhớ để nâng cao trình độ của mình, chúng ta cần phải đào sâu nghiên cứu cả những thứ tưởng chừng rất đơn giản.
Nếu bài viết này có ích hãy chia sẻ nó và tham gia hội anh em Nghiện Lập Trình để giao lưu nhé!

