TYPE | AIR32F103CBT6 | AIR32F103CCT6 | AIR32F103RPT6 |
---|---|---|---|
Flash | 128K | 256K | 256K |
RAM | 32K | 64K | 96K |
Pack | lqfp48 | lqfp48 | lqfp64 |
根據資料手冊, AIR32F103CBT6 和 AIR32F103CCT6 分別帶 32K Byte和 64K Byte 記憶體. 對於48pin封裝的 AIR32F103, 32K和64K的記憶體已經是市面上M3晶片中相當不錯的容量, 至於64pin封裝的AIR32F103RPT6, 96K的記憶體只在市場上的高階型號中出現, 例如雅特力的AT32F403A系列.
但是實際上這兩個型號和 AIR32F103RPT6 一樣, 記憶體空間為96K.
這個隱藏的記憶體空間, 是 Hedley Rainnie 在觀察切換216MHz的過程中發現的. 這個容量也得到了合宙技術的確認.
具體的記錄可以檢視 http://www.hrrzi.com/2022/12/the-air32f103.html. 在切換216MHz的過程中, 在將RCC->RCC_SYSCFG_CONFIG
置零之前, 可以通過SYSCFG->SYSCFG_RSVD0[5]
這個暫存器設定記憶體空間的結束地址. 將這個地址設為 0x20018000 後, 在程式碼中就可以使用 96K Byte 的記憶體容量.
切換216MHz的程式碼
#define SysFreq_Set (*((void (*)(uint32_t, FlashClkDiv , uint8_t, uint8_t))(*(uint32_t *)0x1FFFD00C)))
uint32_t AIR_RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul, FlashClkDiv Latency)
{
volatile uint32_t sramsize = 0;
assert_param(IS_RCC_PLL_SOURCE(RCC_PLLSource));
assert_param(IS_RCC_PLL_MUL(RCC_PLLMul));
*(volatile uint32_t *)(0x400210F0) = BIT(0);//開啟sys_cfg門控
*(volatile uint32_t *)(0x40016C00) = 0xa7d93a86;//解一、二、三級鎖
*(volatile uint32_t *)(0x40016C00) = 0xab12dfcd;
*(volatile uint32_t *)(0x40016C00) = 0xcded3526;
// 這一步記錄了RAM大小
sramsize = *(volatile uint32_t *)(0x40016C18);
*(volatile uint32_t *)(0x40016C18) = 0x200183FF;//設定sram大小, 將BOOT使用對sram開啟
*(volatile uint32_t *)(0x4002228C) = 0xa5a5a5a5;//QSPI解鎖
SysFreq_Set(RCC_PLLMul,Latency ,0,1);
RCC->CFGR = (RCC->CFGR & ~0x00030000) | RCC_PLLSource;
// 在這一步, 將之前的RAM大小再設定回去, 如果把這個sramsize直接改為 0x20018000, 就使得整個96K都可用了
*(volatile uint32_t *)(0x40016C18) = sramsize;
*(volatile uint32_t *)(0x400210F0) = 0;//開啟sys_cfg門控
*(volatile uint32_t *)(0x40016C00) = ~0xa7d93a86;//加一、二、三級鎖
*(volatile uint32_t *)(0x40016C00) = ~0xab12dfcd;
*(volatile uint32_t *)(0x40016C00) = ~0xcded3526;
*(volatile uint32_t *)(0x4002228C) = ~0xa5a5a5a5;//QSPI解鎖
return 1;
}
上面的程式碼用地址表示比較難閱讀, 能換成暫存器表達的都換成暫存器表達後, 看起來會簡單些
uint32_t AIR_RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul, FlashClkDiv Latency)
{
assert_param(IS_RCC_PLL_SOURCE(RCC_PLLSource));
assert_param(IS_RCC_PLL_MUL(RCC_PLLMul));
RCC->RCC_SYSCFG_CONFIG = 1; // Unlock sys_cfg gate control
SYSCFG->SYSCFG_LOCK = 0xa7d93a86; // Unlock from level 1 to 3
SYSCFG->SYSCFG_LOCK = 0xab12dfcd;
SYSCFG->SYSCFG_LOCK = 0xcded3526;
SYSCFG->SYSCFG_RSVD0[5] = 0x200183FF; // Set sram size, enable BOOT for sram
*(__IO uint32_t *)(FLASH_R_BASE + 0x28C) = 0xa5a5a5a5; // Unlock QSPI
AIR_SysFreq_Set(RCC_PLLMul, Latency, 0, 1);
RCC->CFGR = (RCC->CFGR & ~0x00030000) | RCC_PLLSource;
// Restore previous config
SYSCFG->SYSCFG_RSVD0[5] = 0x20018000;
RCC->RCC_SYSCFG_CONFIG = 0; // Lock sys_cfg gate control
SYSCFG->SYSCFG_LOCK = ~0xa7d93a86; // Lock from level 1 to 3
SYSCFG->SYSCFG_LOCK = ~0xab12dfcd;
SYSCFG->SYSCFG_LOCK = ~0xcded3526;
*(__IO uint32_t *)(FLASH_R_BASE + 0x28C) = ~0xa5a5a5a5;// Lock QSPI
return 1;
}
測試96K記憶體的原始碼
DMA_TC_Interrupt_96k_Malloc 和 DMA_TC_Interrupt_96k_Static 這兩個範例分別演示動態和靜態使用超過64K記憶體的情況. 在執行這兩個例子前, 需要對專案程式碼做一些調整
修改 RAM LENGTH 為 96K
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 256K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K <---- 修改這個值為 96K
MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
}
確認啟用了 SYSCLK_FREQ_216MHz 這個宏設定
//#define SYSCLK_FREQ_HSE HSE_VALUE
//#define SYSCLK_FREQ_24MHz 24000000
//#define SYSCLK_FREQ_36MHz 36000000
//#define SYSCLK_FREQ_48MHz 48000000
//#define SYSCLK_FREQ_56MHz 56000000
//#define SYSCLK_FREQ_72MHz 72000000
#define SYSCLK_FREQ_216MHz 216000000 <---- 啟用這個設定
47000 個 uint16_t, 對應了 47K * 2 = 94K 記憶體
動態申請
#define BUFF_SIZE 47000
uint16_t *dma_buf;
...
dma_buf = (uint16_t *)malloc(BUFF_SIZE * sizeof(uint16_t));
printf("Malloc size: %d\r\n", BUFF_SIZE * sizeof(uint16_t));
靜態申請
#define BUFF_SIZE 47000
uint16_t dma_buf[BUFF_SIZE];
需要確保在未完成記憶體容量設定前, 不要使用 dma_buf
據說除了額外的RAM, 還有額外的FLASH, 但是我沒試成功, 在寫入flash後校驗不通過, 也可能我使用的姿勢不對.
原先AIR32F103CBT6只有32K記憶體, 不能跑Helix MP3解碼, 現在的96K記憶體足夠跑兩個, LOL