[2]SWM181-了解官方的工程架构

        尝试了解官方的工程架构,打开Keil,Target配置如下:
FluxBB bbcode 测试
        我们使用的SWM181CBT6,拥有16KB SRAM,240KB Flash,所以我们可以修改一下。物尽其用。
查看数据手册上面的存储器映射表:
FluxBB bbcode 测试
        填写Keil的配置(用于自动生成链接脚本)。
IROM 0X0000 0000,  0X0003 C000 ; IRAM  0X 2000 0000,0x0000 4000
上图:
FluxBB bbcode 测试
        这样就能用上240KB的Flash,16KB SRAM了。

观察startup_xxx.s文件(启动文件),里面做了什么事情呢?
---------------------------------------------------------------------------------------------
(1)开辟栈,并使用标号__initial_sp获得栈顶。
Stack_Size          EQU     0x800;
                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem           SPACE   Stack_Size
__initial_sp
---------------------------------------------------------------------------------------------
(2)开辟堆,并使用__heap_limit获取堆的界限。
Heap_Size           EQU     0x000;
                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit
此处明显堆的大小为0,这样的话,按道理来说是无法使用C库里面的malloc()函数分配内存的。
---------------------------------------------------------------------------------------------
(3)异常向量指定:RESET段。

 AREA    RESET, DATA, READONLY
__Vectors        DCD     Stack_Mem + Stack_Size             ; Top of Stack 栈顶,等于__initial_sp
                DCD     Reset_Handler             ; Reset Handler
                DCD     NMI_Handler             ; NMI Handler
                DCD     HardFault_Handler         ; Hard Fault Handler
                DCD     0
                DCD     0
                DCD     0
                DCD     0
                DCD     0
                DCD     0
                DCD     SRAM_SWITCH
                DCD     SVC_Handler               ; SVCall Handler
                DCD     0
                DCD     0
                DCD     PendSV_Handler            ; PendSV Handler
                DCD     SysTick_Handler           ; SysTick Handler

                ; External Interrupts
                DCD     IRQ0_Handler
                DCD     IRQ1_Handler
                DCD     IRQ2_Handler
                DCD     IRQ3_Handler
                DCD     IRQ4_Handler
                DCD     IRQ5_Handler
                DCD     IRQ6_Handler
                DCD     IRQ7_Handler
                DCD     IRQ8_Handler
                DCD     IRQ9_Handler
                DCD     IRQ10_Handler
                DCD     IRQ11_Handler
                DCD     IRQ12_Handler
                DCD     IRQ13_Handler
                DCD     IRQ14_Handler
                DCD     IRQ15_Handler
                DCD     IRQ16_Handler
                DCD     IRQ17_Handler
                DCD     IRQ18_Handler
                DCD     IRQ19_Handler
                DCD     IRQ20_Handler
                DCD     IRQ21_Handler
                DCD     IRQ22_Handler
                DCD     IRQ23_Handler
                DCD     IRQ24_Handler
                DCD     IRQ25_Handler
                DCD     IRQ26_Handler
                DCD     IRQ27_Handler
                DCD     IRQ28_Handler
                DCD     IRQ29_Handler
                DCD     IRQ30_Handler
                DCD     IRQ31_Handler
__Vectors_End


---------------------------------------------------------------------------------------------
为什么这样设定?
查看sct脚本:工程目录下的输入目录里面存在一个自动生成的KeyLED.sct链接脚本。
脚本的数据来源于,Target设置,作用:指定各段存放的位置。
 

LR_IROM1 0x00000000 0x00006000  {    ; load region size_region
  ER_IROM1 0x00000000 0x00006000  {  ; 芯片Flash映射在0地址
   *.o (RESET, +First)                              ;指定RESET段链接到头部
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  RW_IRAM1 0x20000000 0x00002000  {  ; RW data
   .ANY (+RW +ZI)                                   ;变量,堆栈等链接到此处。
  }
}

因为芯片内存过小,而且这个芯片不适合扩展内存等操作,在内存管理方面便不多做介绍。

CPU上电后,芯片内部自动读取存放在Flash 0地址上面的栈顶地址进而设置堆栈指针。
CPU 内部电压稳定后,发生reset异常,自动跳转到异常的处理函数中。
Reset_Handler   PROC
                EXPORT  Reset_Handler            [WEAK]
                IMPORT  __main
               
                LDR     R0, =__main
                BX     R0
                ENDP

可用看到,这里只有一种操作,那就是跳转到__main()函数里面执行了。
__main()和Main() (以前的ARM9使用ADS编写程序用到)是存在差异的,有兴趣自行百度进行科普。

------------------------------------------------------------------------------------------------------
在main()里面,首先便调用以下函数,设置芯片工作频率。

void SystemInit(void)
{
	uint32_t i;
	
	SYS->CLKEN |= (1 << SYS_CLKEN_OSC_Pos);
	
	switch(SYS_CLK)
	{
		case SYS_CLK_24MHz:			//0 内部高频24MHz RC振荡器
			if(SYS->CLKSEL & SYS_CLKSEL_SYS_Msk)	//当前时钟是高频RC,修改高频RC时钟频率时需要先切到一个稳定时钟源
			{
				switchToRC32KHz();
			}
			switchToRC24MHz();
			break;
		
		case SYS_CLK_6MHz:			//1 内部高频 6MHz RC振荡器
			if(SYS->CLKSEL & SYS_CLKSEL_SYS_Msk)	//当前时钟是高频RC,修改高频RC时钟频率时需要先切到一个稳定时钟源
			{
				switchToRC32KHz();
			}
			switchToRC6MHz();
			break;
		
		case SYS_CLK_48MHz:			//2 内部高频48MHz RC振荡器
			if(SYS->CLKSEL & SYS_CLKSEL_SYS_Msk)	//当前时钟是高频RC,修改高频RC时钟频率时需要先切到一个稳定时钟源
			{
				switchToRC32KHz();
			}
			switchToRC48MHz();
			break;
		
		case SYS_CLK_12MHz:			//3 内部高频12MHz RC振荡器
			if(SYS->CLKSEL & SYS_CLKSEL_SYS_Msk)	//当前时钟是高频RC,修改高频RC时钟频率时需要先切到一个稳定时钟源
			{
				switchToRC32KHz();
			}
			switchToRC12MHz();
			break;
		
		case SYS_CLK_32KHz:			//4 内部低频32KHz RC振荡器
			if((SYS->CLKSEL & SYS_CLKSEL_SYS_Msk) == 0)
			{
				switchToRC24MHz();
			}
			switchToRC32KHz();
			break;
		
		case SYS_CLK_XTAL:			//5 外部XTAL晶体振荡器(2-30MHz)
			if((SYS->CLKSEL & SYS_CLKSEL_SYS_Msk) == 0)
			{
				switchToRC24MHz();
			}
			switchToXTAL();
			break;
	}
	
	for(i = 0;i <10000;i++);		//等待时钟稳定。。。
	
	SystemCoreClockUpdate();
}

以上代码中,存在一条神奇的语句,可能要耗费CPU一点时间。
for(i = 0;i <10000;i++);        //等待时钟稳定。。。
MCU IO引脚上电后会存在默认高电平/低电平等情况,如果板子设计时没有考虑到这个原因导致的影响,可用在这行语句之前指定引脚状态,减少影响。
--------------------------------------------------------------------------------------------------
展开宏:#define SYS_CLK       SYS_CLK_24MHz
可用看到,官方例程里面,MCU默认工作于24MHz。
理论上,可用修改该宏定义为SYS_CLK_48MHz,将MCU工作频率设置为48MHz。但是不知道是否稳定,目前没有尝试。

#define SYS_CLK_24MHz	0	 	//0 内部高频24MHz RC振荡器
#define SYS_CLK_6MHz	1		//1 内部高频 6MHz RC振荡器									
#define SYS_CLK_48MHz	2		//2 内部高频48MHz RC振荡器									
#define SYS_CLK_12MHz	3		//3 内部高频12MHz RC振荡器									
#define SYS_CLK_32KHz	4		//4 内部低频32KHz RC振荡器									
#define SYS_CLK_XTAL	5		//5 外部XTAL晶体振荡器(2-30MHz)

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值