Để mở rộng bộ nhớ RAM cho nhu cầu lưu trữ các dữ liệu của vi điều khiển, người thiết kế dự án cần sử dụng IC nhớ SDRAM để ghép nối với vi điều khiển và thực hiện các cấu hình, khai báo cần thiết để sử dụng bộ nhớ mới này một cách bình thường như bộ nhớ RAM tích hợp.Giao diện Flexible Memory Controller(FMC) của vi điều khiển thường được sử dụng để giao tiếp với SDRAM, và nhiều loại bộ nhớ khác như PSRAM, NAND/NOR FLASH,…
Trong bài viết này, TAPIT chia sẻ cùng các bạn thông tin về bộ nhớ SDRAM, giao diện giao tiếp, các bước để thực hiện cấu hình, khai báo mở rộng bộ nhớ RAM và kết quả thử nghiệm. Bài viết sử dụng bảng mạch STM32F746 Discovery, board mạch này có sẵn IC nhớ SDRAM IS42S32400F.
Các khối chân trong Hình 1 và các cấu tạo IC SDRAM trong Hình 2:
- Address: 12 chân địa chỉ cho địa chỉ hàng và cột . Một lưu ý là trong Hình 2, dù phần cột chỉ dùng 8 chân địa chỉ nhưng vẫn phải có 12 chân địa chỉ để đáp ứng đủ 12 chân cho phần địa chỉ hàng.
- Bank: IC SDRAM này có 4 banks nên cần 2 chân cho địa chỉ Bank là BA0 và BA1
- Data: IC SDRAM IS42S32400F hỗ trợ truyền nhận 32 bits dữ liệu cùng lúc. Tuy nhiên lưu ý là trong thiết kế board của ST như Hình 10, 16 chân đại diện 16 bits cao đã bị nối xuống âm. Do đó, chỉ có thể truyền nhận 16 bits và ½ dung lượng bộ nhớ không thể sử dụng được.
- Các chân control:
- CLK: xung clock cấp cho IC nhớ. Thông số này phải được kiểm tra ở datasheet
- CKE: Clock Enable cho SDRAM
- CS: Chip select
- RAS: Row address strobe hay còn gọi là chân kích hoạt địa chỉ hàng. Khi vi điều khiển cấp địa chỉ hàng cho SDRAM thì kéo chân này xuống mức thấp
- CAS: Column address strobe hay còn gọi là chân kích hoạt địa chỉ cột. Khi vi điều khiển cấp địa chỉ cột cho SDRAM thì kéo chân này xuống mức thấp
- Lưu ý: RAS và CAS không thể đồng thời xuống mức thấp.
- WE: Write enable ra lệnh ghi hay đọc vào SDRAM
- DQM<0,1,2,3> (theo hãng sản xuất chip RAM) hay NBL<0,1,2,3> (theo kí hiệu của ST): Chân chọn byte hay gọi là Data Input/Output Mask. Ví dụ vi điều khiển cần 1 dữ liệu 1 byte nhưng lúc nào cũng có 2 bytes (16 bits) được truyền thì phải mask (mặt nạ) byte không cần thiết. Đối với IC SDRAM, thì có 4 chân DQM, tuy nhiên board STM32F746 DISCO chỉ dùng 16 bits nên chỉ cần 2 chân NBL0/1 còn 2 chân 2 và 3 sẽ được nối xuống âm.
1.Các tham số của SDRAM và cách đọc/sử dụng
1.1. Địa chỉ và bank
- Như đã nói ở phần trên, SDRAM sử dụng địa chỉ theo hàng và cột. Tuy nhiên các thông số về hàng cột được lấy ở đâu?
- Đầu tiên, ta cần xác định chip SDRAM mà chúng ta đang có. Trong trường hợp của tác giả bài viết là STM32F746-DISCO và chip SDRAM là IS42S32400F. Chúng ta cần tải datasheet của chip SDRAM [1].
- Trong datasheet, ta chú ý đến phần Address Table ở Hình 3 bên dưới:
- Ta có thể thấy được kí hiệu và từ đó có được số chân cho hàng, cột và banks
1.2. Clock
- Mỗi chip SDRAM đều có giới hạn về tần số tối đa để có thể hoạt động ổn định. Nếu chạy ở tốc độ cao hơn tần số tối đa, các tham số Timing mà ta bàn ở phần C sẽ quá nhỏ và SDRAM sẽ không thể đáp ứng được tốc độ truyền cao; Hậu quả là dữ liệu ra sẽ bị corrupted.
- Để biết được tần số tối đa mà chip SDRAM có thể hoạt động, ta cần xem phần Key Timing Parameter như Hình 4 dưới:
- Đầu tiên, ta thấy có 3 version: -6, -7 và -75E còn được gọi là Speed/CL variation. Để xác định được thông số trên thì phải coi tên chip RAM; Ví dụ chip IC của tác giả có dòng -6BL như hình 5 dưới:
Hình 5: Speed/CL
- Ở đây ta hiểu Speed/CL của IC này ở mục -6 trong datasheet, B là chỉ dạng Package (BGA), L xác định loại chì hàn cho IC SDRAM (L = SnAgCu cho package BGA).
- Từ đây ta biết được chip SDRAM có thể chạy được ở 2 tần số tối đa với 2 tham số CL (CAS Latency) khác nhau là:
166MHz | CL = 3 |
100MHz | CL = 2 |
- Ở trong bài viết này, tác giả sử dụng tham số là: 100MHz, CL = 2 để dễ cấu hình trong Mục 3 dưới đây. Nếu sử dụng 166MHz, thì phải rất cẩn thận trong việc cấu hình tần số cho core và các ngoại vi khác của vi điều khiển.
1.3.Timing
- Trong SDRAM, việc hiểu và hiệu chỉnh các tham số timing chính xác là vô cùng quan trọng vì nó ảnh hưởng trực tiếp đến độ tin cậy khi truyền dữ liệu.
- Trước khi đọc chi tiết về cái timing phía dưới, các bạn hãy xem sơ qua các bước cũng như lệnh để đọc 1 đơn vị dữ liệu ra khỏi SDRAM ở Hình 6:
- Để cấu hình giao tiếp SDRAM với STM32 qua giao thức FMC, ta có 7 tham số timing sau cần chú ý:
- tMRD(Mode Register Delay Time): Thời gian trễ từ việc set thanh ghi Mode của SDRAM tới lúc lệnh trong thanh ghi được thực thi
- tRAS(Row Address Strobe Time): Thời gian tối thiểu từ lệnh ACTIVE đến lệnh PRECHARGE
- tRC(Row Cycle Time): Thời gian tối thiểu giữa 2 lệnh READ/WRITE liên tiếp nhau khi không cùng 1 page trong SDRAM.
- tDPL(Write Recovery Time): Thời gian tối thiểu từ lệnh WRITE đến PRECHARGE
- tRP(Precharge to Row Time): Thời gian tối thiểu từ lệnh PRECHARGE tới ACTIVATE
- tRCD(Row Column Delay Time): Thời gian tối thiểu từ lúc có lệnh ACTIVE (đưa địa chỉ hàng vào chân địa chỉ) đến lúc địa chỉ Cột được đưa vào chân địa chỉ
- tCAS(Column Access Time): Thời gian tối thiểu từ lệnh READ (địa chỉ hàng được đưa lên chân địa chỉ) cho đến khi dữ liệu được đọc hoặc ghi. Thời gian này còn được gọi với tên gọi khác quen thuộc hơn là CAS Latency hay CL
- Các thông số timing trên chỉ là một phần nhỏ mà chúng ta cần quan tâm khi thiết lập ngoại vi giao tiếp. Thực tế thì có rất nhiều thông số khác được ghi trong Datasheet như Hình 7 ở dưới (Phần lớn các tham số timing được thể hiện bằng cycle-chu kỳ tần số hoạt động của SDRAM):
- Thực tế thì việc đọc/ghi trên SDRAM phức tạp hơn nhiều vì nó còn liên quan đến việc đọc/ghi theo burst (đọc một chuỗi các bytes hay words liên tiếp nhau trong 1 page) cùng với các policies đọc/ghi như open-page/closed-page/limited-open-page/… policies.
- Đối với bài hướng dẫn nãy, vì ở phần Clock ta đã chọn tham số Clock/CL = 100MHz/2 nên toàn bộ tham số timing ở Hình 7 ta phải chọn phần có CAS Latency (CL) là 2 và ở cột “-6”.
2.Cấu hình ngoại vi FMC trên CubeMX
- Dựa vào tần số hoạt động và các thông số timing datasheet để ta có thể cấu hình clock cũng như ngoại vi FMC của vi điều khiển.
- Đầu tiên về clock, ngoại vi FMC được nối trực tiếp vào cầu chia bus AXI ra AHB; Do đó, tần số của ngoại vi SDRAM chung tần số với AHB, với core của vi điều khiển. Chính vì thế, ta cài đặt tần số của HCLK (ngay sau bộ chia tần của AHB) lên 200MHz như Hình 8:
- Có một lưu ý là chúng ta có thể set tần số này thấp hơn 200 MHz, IC SDRAM có thể chạy ổn định ở tần số thấp hơn tần số tối đa. Chỉ khi ta set cao hơn tần số tối đa thì mới xảy ra lỗi dữ liệu.
- Tiếp đến ta cấu hình cho ngoại vi FMC:
- Đầu tiên, ta phải kích hoạt và cấu hình các tham số cơ bản cho ngoại vi FMC như Hình 9:
Hình 9: Cấu hình một số tham số cơ bản cho SDRAM- Kích hoạt “SDRAM 1” lên, nếu có 2 SDRAM thì phải kích hoạt cả “SDRAM 2”. Việc chọn SDRAM 1 hay 2 sẽ ảnh hưởng đến địa chỉ bắt đầu và kết thúc của SDRAM. Ví dụ: SDRAM 1 có không gian địa chỉ từ 0xC000_0000 đến 0xCFFFFFFF còn SDRAM 2 có không gian địa chỉ từ 0xD000_0000 đến 0xDFFFFFFF [8].
- Ở “Clock and chip enable”, ta chọn “SDCKE0+SDNE0”. Thông số này người dùng phải kiểm tra Schematic của board phát triển để biết chính xác. Như Schematic của STM32F746-DISCO ở Hình 20 thì chip SDRAM được kết nối với SDCKE0 và SDNE0.
Hình 10: chip SDRAM trên board STM32F746-DISCO kết nối với SDCKE0 và SDNE0- “Internal bank number: 4 banks”: Thông số này chúng ta kiểm tra trong Datasheet của chip SDRAM, chip SDRAM IS42S32400F có 4 banks
- “Address: 12 bits”: Tương tự như Bank, cần phải có 12 bits đại diện cho 12 chân địa chỉ kết nối với SDRAM
- “Data: 16 bits”: chip SDRAM IS42S32400F hỗ trợ 32 bits dữ liệu nhưng 16 chân tương ứng 16 bits cao đã bị nối đất. chính vì thế, ta chỉ có thể để 16 bits.
- “Byte enable: 16-bit byte enable”: Khi kích hoạt mục này, ta cho phép 2 chân FMC_NBL0/1 ở Hình 20 được sử dụng để mask đi các byte không cần thiết trong 16 bit dữ liệu được truyền đi mỗi lần đọc/ghi. Việc mask bằng phần cứng giúp giảm thời gian và giảm tải cho lõi vi xử lý.
- Sau khi cấu hình được các tham số cơ bản, chúng ta phải cấu hình chi tiết về địa chỉ, clock và timing như ở Hình 11:
Hình 11: Cấu hình địa chỉ, clock và timing
- “Number of column address… 8 bits”: Được thể hiện ở Hình 2 phía trên
- “Number of row address bits 12 bits”: Được thể hiện ở Hình 2 phía trên
- “CAS latency 2 memory clock cycles”: Ở Hình 7, ta thấy rằng CL cần 2 cycle tối thiểu nên ta chọn “2 memory clock cycles”
- “SDRAM common clock 2 HCLK clock cycles”: chip SDRAM chạy ở tần số 100MHz trong khi HCLK chúng ta thiết lập ở Hình 8 là 200MHz nên ta phải chọn là “2 HCLK clock cycles” để chia đôi 200MHz ra
- “SDRAM common burst read Enabled”: Kích hoạt chế độ đọc theo burst. Nghĩa là các từ liên tiếp nhau trong cùng page của chip SDRAM sẽ được đọc mà không cần phải thực hiện lệnh PRECHARGE. Điều này sẽ tăng tốc độ đọc tuần tự vào 1 mảng dữ liệu
- “SDRAM common read pip… 0 HCLK clock cycles”: Thời gian trễ khi đọc hai words 16 bits liên tiếp ra từ SDRAM. Có thể hiểu đây là thời gian vi điều khiển chờ để SDRAM chuẩn bị dữ liệu khi đọc theo burst. Vì chip SDRAM IS42S32400F không yêu cầu nên ta để là 0
- “Load mode register to acti… 2”: Đây chính là tMRD; Kết hợp Hình 16, ta để là 2
- “Exit self-refresh delay 7”: Đây là thời gian delay khi chip SDRAM dừng việc refresh tự động đến khi ta có thể kích hoạt lệnh ACTIVE. Thông số này được ghi trong bảng “AC ELECTRICAL CHARACTERISTICS” của chip IS42S32400F như Hình 22. Tuy nhiên, nhà sản xuất ghi là 70ns thì ta hiểu là 7 chu kì của SDRAM ở tần số SDRAM là 100MHz
Hình 12: Exit self-refresh delay
- “Self-refresh time 5”: Đây chính là tRAS; Kết hợp Hình 16, ta để là 5
- “SDRAM common row cycle 6”: Đây chính là tRC; Kết hợp Hình 16, ta để là 6
- “Write recovery time 3”: Đây chính là tDPL; Kết hợp Hình 16, ta để là 2. Tuy nhiên trong STM32 yêu cầu tDPL≥ tRAS– tRCD=5 (phía trên) – 2 (phía dưới) = 3
- “SDRAM common row prec… 2”: Đây chính là tRP; Kết hợp Hình 16, ta để là 2
- “Row to column delay 2”: Đây chính là tRCD; Kết hợp Hình 16, ta để là 2
*Lưu ý: Phải kiểm tra toàn bộ chân của FMC đã khớp với các chân được vẽ trong Schematic của board chưa. Nếu chưa, phải tiến hành tìm các chân thay thế phù hợp.
3. Khởi tạo module SDRAM trong hàm MX_FMC_Init()
- Khi sinh code thì STM32CubeIDE-MX sẽ sinh ra một hàm “void MX_FMC_Init(void)”. Hàm này chỉ mới khởi tạo ngoại vi FMC, ta cần phải viết thêm các đoạn mã để ngoại vi FMC khởi tạo các chế độ hoạt động cho SDRAM; Nếu không thì SDRAM sẽ không thể được đọc/ghi.
- Đoạn mã hàm “void MX_FMC_Init(void)” sau khi sửa lại như bên dưới:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
<span style="font-family: arial, helvetica, sans-serif;">void MX_FMC_Init(void) { /* USER CODE BEGIN FMC_Init 0 */ /* USER CODE END FMC_Init 0 */ FMC_SDRAM_TimingTypeDef SdramTiming = {0}; /* USER CODE BEGIN FMC_Init 1 */ FMC_SDRAM_CommandTypeDef Command; /* USER CODE END FMC_Init 1 */ /** Perform the SDRAM1 memory initialization sequence */ hsdram1.Instance = FMC_SDRAM_DEVICE; /* hsdram1.Init */ hsdram1.Init.SDBank = FMC_SDRAM_BANK1; hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8; hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12; hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16; hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2; hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2; hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE; hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0; /* SdramTiming */ SdramTiming.LoadToActiveDelay = 2; SdramTiming.ExitSelfRefreshDelay = 7; SdramTiming.SelfRefreshTime = 5; SdramTiming.RowCycleDelay = 6; SdramTiming.WriteRecoveryTime = 3; SdramTiming.RPDelay = 2; SdramTiming.RCDDelay = 2; if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK) { Error_Handler( ); } /* USER CODE BEGIN FMC_Init 2 */ __IO uint32_t tmpmrd =0; /* Step 1: Configure a clock configuration enable command */ Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; Command.AutoRefreshNumber = 1; Command.ModeRegisterDefinition = 0; /* Send the command */ HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT); /* Step 2: Insert 100 us minimum delay */ /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */ HAL_Delay(1); /* Step 3: Configure a PALL (precharge all) command */ Command.CommandMode = FMC_SDRAM_CMD_PALL; Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; Command.AutoRefreshNumber = 1; Command.ModeRegisterDefinition = 0; /* Send the command */ HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT); /* Step 4 : Configure a Auto-Refresh command */ Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; Command.AutoRefreshNumber = 8; Command.ModeRegisterDefinition = 0; /* Send the command */ HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT); /* Step 5: Program the external memory mode register */ tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 | SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | SDRAM_MODEREG_CAS_LATENCY_2 | SDRAM_MODEREG_OPERATING_MODE_STANDARD | SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; Command.AutoRefreshNumber = 1; Command.ModeRegisterDefinition = tmpmrd; /* Send the command */ HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT); /* Step 6: Set the refresh rate counter */ /* (15.62 us x Freq) - 20 */ /* Set the device refresh counter */ hsdram1.Instance->SDRTR |= ((uint32_t)((1292)<< 1)); /* USER CODE END FMC_Init 2 */ }</span> |
- Toàn bộ đoạn code trong phần “USER CODE BEGIN/END FMC_Init 1” và “USER CODE BEGIN/END FMC_Init 2” là các đoạn mã ta cần thêm vào.
- Như ta thấy trong phần ”USER CODE BEGIN/END FMC_Init 2”, có steps cần được thực hiện:
- Step 1: Gửi lệnh kích hoạt clock cho các mảng nhớ trong SDRAM
- Step 2: Chờ ít nhất là 100μs
- Step 3: Precharge toàn bộ các hàng trong SDRAM
- Step 4: Kích hoạt chế độ Auto-Refresh trong SDRAM. Nếu không kích hoạt chế độ này thì phải lập trình cho vi điều khiển để gửi lệnh refresh định kỳ tới SDRAM còn không thì SDRAM sẽ bị mất dữ liệu
- Step 5: Cấu hình Mode/Burst/CL cho SDRAM
- Step 6: Cấu hình counter bên trong SDRAM cho chế độ Auto-Refresh ở bước 4. Từ Hình 11, chip IS42S32400F gồm 4096 hàng và dựa vào Datasheet của chip ở Hình 22, thời gian để refresh toàn bộ là 64ms ở nhiệt độ < 70 độ. Ta có (64ms/4096)*100MHz – 20 ≃ 1292
-
Edit file “main.h”
- Ở bước 4, ta thấy có 1 số macro trong phần “USER CODE BEGIN/END FMC_Init 2” được sử dụng nhưng chưa được khai báo. Vì thế, ta cần phải thêm các macros này vào trong “main.h” như đoạn code dưới đây:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<span style="font-family: arial, helvetica, sans-serif;">/* Exported types ------------------------------------------------------------*/ /* USER CODE BEGIN ET */ typedef enum {PASSED = 0, FAILED = !PASSED} TestStatus_t; /* Exported constants --------------------------------------------------------*/ #define SDRAM_BANK_ADDR ((uint32_t)0xC0000000) /* #define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_8 */ #define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_16 #define SDCLOCK_PERIOD FMC_SDRAM_CLOCK_PERIOD_2 /* #define SDCLOCK_PERIOD FMC_SDRAM_CLOCK_PERIOD_3 */ #define SDRAM_TIMEOUT ((uint32_t)0xFFFF) #define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000) #define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001) #define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002) #define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004) #define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000) #define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008) #define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020) #define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030) #define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000) #define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000) #define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200) /* USER CODE END ET */</span> |
- Toàn bộ các macro để thiết lập cấu hình cho SDRAM đều được tham khảo từ Datasheet của chip SDRAM. Nếu board được sử dụng là các kit phát triển của ST thì trong file “main.h” trong các ví dụ của ST đều có phần này.
-
Cấu hình trong file Linker
- Đối với mục Memory trong Linker, ta thêm mục SDRAM như đoạn mã dưới đây:
1 2 3 4 5 6 |
<span style="font-family: arial, helvetica, sans-serif;">MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K SDRAM (rw) : ORIGIN = 0xC0000000, LENGTH = 8M }</span> |
- Ta thêm vùng nhớ để sử dụng khi khai báo biến:
1 2 3 4 5 6 7 |
<span style="font-family: arial, helvetica, sans-serif;">.sdram_section (NOLOAD): { . = ALIGN(4); *(.buffer) *(.buffer*) . = ALIGN(4); } >SDRAM</span> |
Kiểm tra khả năng đọc ghi của SDRAM
- Ta thêm đoạn code sau vào hàm “main” trong file “main.c”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<span style="font-family: arial, helvetica, sans-serif;">/* USER CODE BEGIN PD */ #define EXTERNAL_SDRAM __attribute__((section(".buffer"))) /* USER CODE END PD */ /* USER CODE BEGIN PV */ EXTERNAL_SDRAM uint8_t count = 0; /* USER CODE END PV */ /* USER CODE BEGIN 2 */ memset((void*)0xC0000000,1,0x007ffffe); //Chạy theo từng byte /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { count++; HAL_Delay(500); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ }</span> |
Ta cho debug thử và dừng ngay câu lệnh đầu tiên trong hàm “while(1)” như Hình 23. Sau đó vào mục Memory như Hình 14, ta thấy toàn bộ các byte trong SDRAM đã được set về 1 như mong muốn tại hàm memset.
- Để test đọc/ghi, ta cho chương trình chạy và tiếp tục dừng ở lệnh đầu trong while(1). Vì biến count là biến 8 bits đầu tiên trong SDRAM nên khi chạy qua lệnh “count++”, ta mong muốn byte đầu tiên trong SDRAM được tăng lên 1 đơn vị. Kết quả được cho thấy ở Hình 16
Hình 16: Byte đầu được tăng từ 1 lên 2
Đến đây, chúng ta đã làm quen và thực hiện được việc đọc/ghi trên SDRAM. Phần tiếp theo sau đây sẽ hướng dẫn các bạn mở rộng bộ nhớ Flash ngoài.
Nhóm tác giả
Ng.Q.Phương
Ng.H.N.Thương
Ng.H.Phúc