Tổ chức bộ nhớ Flash trên chip STM32F411VE

Kiến trúc hệ thống của chip STM32F411VE:

Hệ thống của chip STM32F411VE gồm 6 masters và 5 slaves được kết nối với nhau thông qua một ma trận bus đa lớp AHB 32-bit. Thông qua ma trận bus, các master có thể truy cập và thực hiện các hoạt động lên slave ngay cả khi một số ngoại vi đang hoạt động ở tốc độ cao. 6 masters gồm:  Cortex®-M4 với I-bus, D-bus và S-bus của lõi FPU;  DMA1 memory bus, DMA2 memory bus và DMA2 peripheral bus. 5 slaves gồm: ICode bus và DCode bus của bộ nhớ Flash nội; SRAM; APB1 peripharals và APB2 peripharals.

[HỌC ONLINE: LẬP TRÌNH VI ĐIỀU KHIỂN STM32, VI XỬ LÝ ARM CORTEX – M]

I-bus: thực hiện nhiệm vụ kết nối Instruction bus (của Cortex®-M4 với FPU) đến ma trận Bus để lấy các câu lệnh từ bộ nhớ Flash hoặc SRAM.

D-bus: thực hiện nhiệm vụ kết nối Data bus (của Cortex®-M4 với FPU) đến ma trận Bus để tải các câu lệnh xuống hoặc truy cập debug từ bộ nhớ Flash hoặc SRAM.

S-bus: kết nối bus hệ thống của Cortex®-M4 với FPU đến ma trận Bus để truy cập dữ liệu trên một ngoại vi hoặc trên SRAM. Ngoài ra bus này còn được dùng để lấy các câu lệnh giống I-bus nhưng kém hiệu quả hơn.

DMA memory bus: bus này được sử dụng để truyền nhận dữ liệu với bộ nhớ Flash hoặc SRAM. Đối với DMA memory bus 2 (S4) còn có thể đọc thêm dữ liệu từ các ngoại vi AHB1/AHB2 bao gồm các ngoại vi APB.

DMA peripheral bus: bus này được bộ DMA sử dụng để truy cập vào các ngoại vi AHB hoặc để chuyển dữ liệu giữa memory-memory với nhau.

Tổng quan về bộ nhớ Flash của chip STM32F411VE:

Giao diện bộ nhớ Flash (Flash memory interface) quản lý việc truy cập của các bus I-Code và D-Code AHB CPU vào bộ nhớ Flash. Nó thực hiện các hoạt động xóa và lập trình bộ nhớ Flash và các cơ chế bảo vệ đọc/ghi bộ nhớ Flash.

Tổ chức bộ nhớ Flash của chip STM32F411VE:

– Khối bộ nhớ chính được chia làm các sectors: 4 sectors 16 KBytes/1 sector, 1 sector 64 Kbytes, 3 sectors 128KByte/1 sector.

– System memory 30 Kbytes

– OTP cho dữ liệu người dùng.

– Option bytes.

Read interface:

Để đọc chính xác dữ liệu từ bộ nhớ Flash, số lượng các trạng thái chờ/độ trễ (LATENCY) phải được lập trình trong thanh ghi FLASH_ACR (Flash access control register) đúng với khoảng điện áp cung cấp của thiết bị và tần số clock của CPU (HCLK). Mối liên hệ giữa trạng thái chờ (wait state), supply voltage (điện áp cung cấp) và tần số clock (HCLK) được cho ở bảng sau:

Sau khi reset, HCLK = 16 MHz và WS = 0. Người sử dụng có thể điều chỉnh số lượng trạng thái chờ ứng với tần số phù hợp bằng cách can thiệp vào các thanh ghi FLASH_ACR để thay đổi giá trị WS và thanh ghi RCC_CFGR để thay đổi tần số CPU.

Erase and program operations

Đối với các hoạt động ghi và xóa bộ nhớ, tần số clock bộ CPU phải đạt ít nhất 1 MHz. Nếu hoạt động xóa hoặc ghi đang diễn ra nhưng vẫn có yêu cầu đọc bộ nhớ thì sẽ dẫn đến trình trạng đường Flash memory bus bị đình trệ, vì vậy hoạt động đọc được diễn ra chính xác một khi không thực hiện việc xóa hoặc ghi bộ nhớ.

1. Xóa bộ nhớ

Có 2 loại xóa bộ nhớ Flash là xóa theo sector và xóa toàn bộ Flash (mass erase). Để xóa sector cần thực hiện các bước sau:

– Kiểm tra có hoạt động nào đang diễn ra tại bộ nhớ Flash hay không bằng cách check bit BSY trong thanh ghi FLASH_SR

– Set bit SER (Sector Erase) lên 1 và chọn 1 sector trong bộ nhớ chính (main memory) bằng cách ghi giá trị vào thanh ghi SNB (Sector Number) tại FLASH_CR. Thanh ghi SNB có 4 bits, từ sector 0 đến sector 7 có các giá trị tương ứng 0x0000 đến 0x0111

– Set bit STRT trong thanh ghi FLASH_CR

– Đợi đến khi bit BSY về 0.

Để xóa mass:

– Kiểm tra có hoạt động nào đang diễn ra tại bộ nhớ Flash hay không bằng cách check bit BSY trong thanh ghi FLASH_SR

– Set bit MER và bit STRT trong thanh ghi FLASH_CR lên 1

– Đợi đến khi bit BSY về 0.

Nếu các bit MER và SER đều được set lên 1 thì MCU sẽ thực hiện việc xóa toàn bộ Flash.

* Hàm xóa sector/mass trong thư viện HAL: Ở mục Function, các bạn tìm đến file stm32f4xx_hal_flash_ex.c sau đó kích đúp chuột vào hàm HAL_FLASHEx_Erase.

Ở hàm này ta truyền vào 2 tham số là pEraseInitSectorError:

– FLASH_EraseInitTypeDef  *pEraseInit: pEraseInit là con trỏ trỏ đến struct FLASH_EraseInitTypeDef chứa các thông tin cấu hình để xóa.

uint32_t  *SectorError: là con trỏ trỏ tới sector bị lỗi nếu quá trình xóa bộ nhớ xảy ra lỗi. Giá trị mặc định của con trỏ này bằng 0xFFFFFFFF, nếu kết thúc quá trình xóa mà không xảy ra bất kì lỗi nào thì giá trị của con trỏ này sẽ không bị thay đổi.

Giá trị trả về: HAL_OK, HAL_ERROR, HAL_BUSY hoặc HAL_TIMEOUT

Hàm FLASH_WaitForLastOperation() mục đích check bit BSY trong thanh ghi FLASH_SR, đợi đến khi nào bit FLASH_FLAG_BSY được RESET thì sẽ thoát khỏi hàm này.

Nếu HAL_FLASHEx_Erase() được dùng để xóa toàn bộ vùng flash người dùng thì hàm FLASH_MassErase() sẽ được thực hiện, ngược lại hàm FLASH_Erase_Sector() sẽ được thực hiện. Sau đó đợi bit BSY được RESET và xóa bit SER/MER trong thanh ghi FLASH_CR về 0 để kết thúc quá trình xóa flash.

2. Ghi vào bộ nhớ

Việc ghi bộ nhớ cần quan tâm đến ghi bao nhiêu bit để không xảy ra lỗi. Nếu số bit dữ liệu vượt quá số bit cho phép, cờ báo lỗi sẽ được set lên 1. Số bit cho phép được lập trình tại trường PSIZE 2 bit.

Tuy nhiên PSIZE bị giới hạn bởi điện áp cung cấp và điện áp cung cấp VPP bên ngoài (nếu có).

Các bước ghi dữ liệu vào bộ nhớ Flash:

–  Kiểm tra có hoạt động nào đang diễn ra tại bộ nhớ Flash hay không bằng cách check bit BSY trong thanh ghi FLASH_SR

– Set bit PG trong thanh ghi FLASH_CR lên 1

– Ghi dữ liệu vào thanh ghi bộ nhớ

– Đợi đến khi bit BSY về 0.

Các lỗi có thể xảy ra trong quá trình ghi bộ nhớ:

– Lỗi ghi dữ liệu vượt quá 128 bits, lúc này hoạt động ghi sẽ không được thực hiện và cờ PGAERR (program alignment error flag) được set lên 1.
– Lỗi truy cập dữ liệu không phù hợp với số bit cho phép đã chọn (x8, x16, x32 or x64). Lúc này hoạt động ghi sẽ không được thực hiện và cờ PGPERR (program parallelism error flag) được set lên 1.

– Nếu việc thực hiện ghi flag không diễn ra theo trình tự (ví dụ ghi Flash nhưng bit PG không được set) thì hoạt động sẽ bị bỏ qua và cờ  PGSERR (program sequence error flag) được set lên 1.

* Hàm ghi dữ liệu vào bộ nhớ Flash trong thư viện HAL:

Hàm này có 3 tham số là TypeProgram, AddressData:

uint32_t TypeProgram: tùy vào độ dài của dữ liệu là 8 bits/16 bits/32 bits hay 64 bits mà bạn điền vào các giá trị FLASH_TYPEPROGRAM_BYTE hoặc FLASH_TYPEPROGRAM_HALFWORD hoặc FLASH_TYPEPROGRAM_WORD hoặc FLASH_TYPEPROGRAM_DOUBLEWORD tương ứng.

uint32_t Address: địa chỉ lưu dữ liệu trên.

uint64_t Data: dữ liệu cần lưu.

Giá trị trả về: HAL_OK, HAL_ERROR, HAL_BUSY hoặc HAL_TIMEOUT

Option bytes:

Option bytes là tập hợp các byte được dùng để cấu hình các chế độ bảo vệ đọc/ghi (read/write protection), mức độ BOR, watchdog phần mềm/phần cứng và reset lại MCU nếu thiết bị ở chế độ Standby hoặc Stop mode. Vùng Option bytes gồm 16 bytes, có địa chỉ từ 0x1FFFC000 đến 0x1FFFC00F.

– Read protection (RDP): Có 3 level RDP như sau

+ Level 0: no read protection. Ở level này các hoạt động đọc diễn ra ở bộ nhớ Flash đều được cho phép trong tất cả các cấu hình khởi động (Flash user boot, debug or boot from RAM). Để vào chế độ này MCU phải ghi giá trị 0xAA vào thanh ghi RDP.

+ Level 1: read protection enabled. Đây là level mặc định khi Option bytes bị reset hoặc khi ghi giá trị bất kì trừ 0xAA và 0xCC vào RDP. Khi read protection được set, các hoạt động truy cập bộ nhớ Flash như đọc/xóa/ghi trong chế độ debug, booting từ RAM hoặc từ bộ bootloader sẽ không được thực hiện. Tuy nhiên nếu khởi động từ bộ nhớ Flash thì các việc truy cập trên vẫn được cho phép.

+ Level 2: debug/chip read protection disabled. Khi level 2 được set, mọi tính năng sẽ được giữ nguyên gần giống level 1. Tuy nhiên hoạt động bảo vệ đọc bộ nhớ của level 2 là một hoạt động không thể đảo ngược, nếu như ở level 1 người dùng có thể chuyển từ level 1 về level 0 (điều này gây ra mass erase) nhưng đối với level 2 người dùng không thể cấu hình về level 1 hoặc level 0. Ngoài ra Option bytes ở level 2 không thể thay đổi giá trị như level 1.

Hàm read protection Flash trong thư viện HAL:

Tham số đầu vào là OB_RDP_LEVEL_0 (Không bảo vệ), OB_RDP_LEVEL_1 (Bảo vệ đọc của bộ nhớ), OB_RDP_LEVEL_2 (Bảo vệ toàn bộ chip).

Giá trị trả về: HAL_OK, HAL_ERROR, HAL_BUSY hoặc HAL_TIMEOUT

– Write protections

Chức năng này dùng để bảo vệ tối đa 7 user sectors trong bộ nhớ Flash trước những hoạt động ghi không mong muốn. Khi tính năng này được bật, mọi hoạt động ghi hoặc xóa bộ nhớ sẽ không thực hiện được, do đó không thể thực hiện mass erase nếu có ít nhất một sector bật chế độ write protection. Nếu xóa hoặc ghi bộ nhớ Flash trong khi chế độ bảo vệ ghi vẫn được bật thì cờ báo lỗi WRPERR (Write Protection Error) sẽ được bật trong thanh ghi FLASH_SR.

Hàm write protection Flash trong thư viện HAL:

Hàm này có 2 tham số là WRPSector và Banks:

uint32_t WRPSector: các sector cần được bảo vệ ghi

uint32_t Banks: đối với chip STM32F411VE ta truyền vào giá trị FLASH_BANK_1

Giá trị trả về: HAL_OK, HAL_ERROR, HAL_BUSY hoặc HAL_TIMEOUT

One-time programmable bytes (OTP)

Đây là nơi người dùng lưu trữ dữ liệu và vùng dữ liệu này không thể bị xóa đi. Vùng OTP được chia làm 16 blocks dữ liệu, mỗi block gồm 32 bytes và 1 lock block gồm 16 bytes dùng để lock hoặc unlock 16 blocks dữ liệu trên. Các block dữ liệu có thể được lập trình lại bằng cách ghi giá trị 0x00 vào OTP lock byte tương ứng (LOCKBi với 0 <= i <= 15 tương ứng với Block0 – Block15) và ngược lại nếu muốn lock các dữ liệu trên thì ghi giá trị 0xFF.

Thực hành: Sử dụng một số hàm hỗ trợ lập trình bộ nhớ Flash trong thư viện HAL để ghi một chuỗi kí tự bất kì vào bộ nhớ Flash và dùng phần mềm STM32 ST-LINK Utility để kiểm tra giá trị tại địa chỉ đã ghi có đúng với chuỗi đã cho hay không.