W801|芯片规格书|寄存器手册|总线|时钟|主频|学习(5-1):W801-SDK启动分析之芯片规格书及寄存器手册阅读笔记
W801 默认程序是从内部FLASH 中开始运行的。
(具体执行流程及.ELF文件可参考:FLASH算法|.elf文件|基本类型- FLASH算法文件介绍)
SDK所采用的编译工具链为csky-elfabiv2。链接文件是:gcc_csky.ld。
关键字ENTRY所指向的入口是Reset_Handler,即启动时先进行复位操作,之后进入启动程序,执行startup.S。
startup.S 是SDK的启动文件,位于:G:\bsp\W800_aos\W80X_SDK_v1.00.10\platform\arch\xt804\bsp\startup.S
smartl的启动文件应与GCC一起用于CSKY嵌入式处理器,SDK启动时,先运行sys目录下的startup.S。
#include
.section .vectors
/*内部中断 */
.long SDIO_IRQHandler /* 0: SDIO */
.long MAC_IRQHandler /* 1: MAC */
.long RF_Cfg_IRQHandler /* 2: RF Cfg */
.long SEC_IRQHandler /* 3: SEC */
.long DMA_Channel0_IRQHandler /* 4: DMA_Channel0 */
.long DMA_Channel1_IRQHandler /* 5: DMA_Channel1 */
.long DMA_Channel2_IRQHandler /* 6: DMA_Channel2 */
.long DMA_Channel3_IRQHandler /* 7: DMA_Channel3 */
.long DMA_Channel4_7_IRQHandler /* 8: DMA_Channel4_7 */
.long DMA_BRUST_IRQHandler /* 9: DMA_BRUST */
.long I2C_IRQHandler /* 10: IIC */
.long ADC_IRQHandler /* 11: SD ADC */
.long SPI_LS_IRQHandler /* 12: LS SPI */
.long SPI_HS_IRQHandler /* 13: HS SPI */
.long GPIOA_IRQHandler /* 14: GPIOA */
.long GPIOB_IRQHandler /* 15: GPIOB */
.long USART_IRQHandler /* 16: UART0 */
.long USART1_IRQHandler /* 17: UART1 */
.long USART2_IRQHandler /* 18: UART2&7816 */
.long USART3_5_IRQHandler /* 19: USART3_5 */
.long BLE_IRQHandler /* 20: BLE */
.long BT_IRQHandler /* 21: BT */
.long PWM_IRQHandler /* 22: PWM */
.long I2S_IRQHandler /* 23: I2S */
.long SDIO_HOST_IRQHandler /* 24: SDIO HOST */
.long CORET_IRQHandler /* 25: CoreTIM */
.long RSA_IRQHandler /* 26: RSA */
.long GPSEC_IRQHandler /* 27: GPSEC */
.long FLASH_IRQHandler /* 28: Flash */
.long PMU_IRQHandler /* 29: PMU */
.long TIM0_5_IRQHandler /* 30: Timer0_5 */
.long WDG_IRQHandler /* 31: Watch dog */
接着运行系统初始化程序:
主要执行3个初始化进程:
#ifndef __NO_SYSTEM_INIT
jbsr SystemInit
#endif
SystemInit执行G:\bsp\W800_aos\W80X_SDK_v1.00.10\platform\arch\xt804\bsp\system.c
引入必要的头文件:
#include
#include "csi_core.h"
#include "wm_regs.h"
#include "wm_cpu.h"
extern int32_t g_top_irqstack;
g_top_irqstack:
.section .vdata
.align 10
.globl irq_vectors
.type irq_vectors, @object
irq_vectors:
.space CONFIG_IRQ_VECTOR_SIZE
.size irq_vectors, . - irq_vectors
.globl irq_vectors_end
irq_vectors_end:
extern uint32_t csi_coret_get_load(void);
函数体:
功能:获取核心计时器重新装载值
返回值:核心计时器值
__STATIC_INLINE uint32_t csi_coret_get_load(void)
{
return CORET->LOAD;
}
extern uint32_t csi_coret_get_value(void);
函数体:
功能:获取核心计时器计数器值
返回值: 核心计时器计数器值
__STATIC_INLINE uint32_t csi_coret_get_value(void)
{
return CORET->VAL;
}
主要完成采用UART0或UART1串口波特率及端口设置。
#ifndef __NO_BOARD_INIT
jbsr board_init
#endif
void board_init(void)
{
#if USE_UART0_PRINT
/* use uart0 as log output io */
uart0Init(115200);
set_printf_port(0);
#else
uart1_io_init();
/* use uart1 as log output io */
uart1Init(115200);
set_printf_port(1);
#endif
}
static void uart0Init (int bandrate)
{
unsigned int bd;
NVIC_DisableIRQ(UART0_IRQn);
NVIC_ClearPendingIRQ(UART0_IRQn);
bd = (APB_CLK/(16*bandrate) - 1)|(((APB_CLK%(bandrate*16))*16/(bandrate*16))<<16);
tls_reg_write32(HR_UART0_BAUD_RATE_CTRL, bd);
tls_reg_write32(HR_UART0_LINE_CTRL, UART_BITSTOP_VAL | UART_TXEN_BIT | UART_RXEN_BIT);
tls_reg_write32(HR_UART0_FLOW_CTRL, 0x00); /* Disable afc */
tls_reg_write32(HR_UART0_DMA_CTRL, 0x00); /* Disable DMA */
tls_reg_write32(HR_UART0_FIFO_CTRL, 0x00); /* one byte TX/RX */
// tls_reg_write32(HR_UART0_INT_MASK, 0x00); /* Disable INT */
}
位于G:\bsp\W800_aos\W80X_SDK_v1.00.10\platform\arch\xt804\libc\libc_port.c中。
函数定义:
void set_printf_port(unsigned char port)
{
if(port == 0)
{
printf_port = 0;
}
else if(port == 1)
{
printf_port = 1;
}
else
{
printf_port = 0xff;
}
}
static void uart1Init (int bandrate)
{
unsigned int bd;
NVIC_DisableIRQ(UART1_IRQn);
NVIC_ClearPendingIRQ(UART1_IRQn);
bd = (APB_CLK/(16*bandrate) - 1)|(((APB_CLK%(bandrate*16))*16/(bandrate*16))<<16);
tls_reg_write32(HR_UART1_BAUD_RATE_CTRL, bd);
tls_reg_write32(HR_UART1_LINE_CTRL, UART_BITSTOP_VAL | UART_TXEN_BIT | UART_RXEN_BIT);
tls_reg_write32(HR_UART1_FLOW_CTRL, 0x00); /* Disable afc */
tls_reg_write32(HR_UART1_DMA_CTRL, 0x00); /* Disable DMA */
tls_reg_write32(HR_UART1_FIFO_CTRL, 0x00); /* one byte TX/RX */
tls_reg_write32(HR_UART1_INT_MASK, 0x00); /* Disable INT */
}
static void uart1_io_init(void)
{
uint32_t temp;
/* PB6.7 AF Close */
temp = tls_reg_read32(HR_GPIOB_AFSEL);
temp &= ~0xC0;
tls_reg_write32(HR_GPIOB_AFSEL, temp);
/* PB6.7 AF Open opt1 */
temp = tls_reg_read32(HR_GPIOB_AFSEL);
temp |= 0xC0;
tls_reg_write32(HR_GPIOB_AFSEL, temp);
temp = tls_reg_read32(HR_GPIOB_AFS0);
temp &= ~0xC0;
tls_reg_write32(HR_GPIOB_AFS0, temp);
temp = tls_reg_read32(HR_GPIOB_AFS1);
temp &= ~0xC0;
tls_reg_write32(HR_GPIOB_AFS1, temp);
}
jbsr main
.size Reset_Handler, . - Reset_Handler
之后跳转至系统主程序文件(wm_main.c)进行主频、PMU等初始化过程:G:\bsp\W800_aos\W80X_SDK_v1.00.10\platform\sys\wm_main.c
引自:ARM汇编指令学习—基于启动文件startup.S分析
以 . 开头一般是伪汇编/操作指令,形如:
.section伪操作来定义一个段,形如:
.section .testsection //定义一个testsection段
汇编系统预定义了一些段名:
.text:代码段
.data:初始化数据段
.bss:未初始化的数据段
.rodata:只读数据段
.global:定义一个全局符号,通常是为ld使用。例子如下:
.global _start
_start: //_start符号,汇编器在翻译汇编程序时会计算每个数据对象和每条指令的地址,当看到这样一个符号定义时,就把它后面一条指令的地址作为这个符号所代表的地址
ldr r0, =0x12 @r0=0x12
//.global 是伪操作,表示_start 是一个全局标号且是一个符号(Symbol),符号在汇编程序中代表一个地址,可以用在指令中,汇编程序经过汇编器的处理之后,所有的符号都被替换成它所代表的地址值
注:" : "前的为标号
.byte 定义单字节数据,比如.byte 0x12。
.short 定义双字节数据,比如.short 0x1234。
.long 定义一个 4 字节数据,比如.long 0x12345678。
.equ 赋值语句,格式为:.equ 变量名,表达式,比如.equ num, 0x12,表示 num=0x12。//相当于#define num 0x12
.align 数据字节对齐,比如:.align 4 表示 4 字节对齐。
.end 表示源文件结束。
.global 定义一个全局符号,格式为:.global symbol,比如:.global _start。
.if … .else … .endif 条件预编译
.abort 停止汇编
.include 指定的头文件, 可以把一个汇编常量定义放在头文件中,比如:.include “file”
注:伪汇编指令不是真正的指令,并没有与之对应的的机器码,不会被执行。伪指令所起的作用主要是对汇编过程进行控制,只用于汇编过程中为汇编程序提供汇编信息。