本帖最后由 dvd1478 于 2014-5-21 09:11 编辑
SAMG53-XPRO 是第一次接触,说实话,Atmel 的产品也是第一次接触,虽然以前有玩过AVR系列的芯片,但也没有深入的了解。Atmel Studio 软件也是为AVR新建了一个模板,然后就没有深入的了解。这次借用https://www.cirmall.com/bbs/thread-29707-1-1.html 申请到的评估板的机会好好来了解一下,Atmel 的产品,以及Atmel Studio 软件的应用。由于初学习,一步一步记录下自己的过程,以方便与大家一起分享,希望大家能多拍砖,共同进展。
[体验篇一]ATSAMG53 Xplained Pro 开箱验货
https://www.cirmall.com/bbs/forum.php?mod=viewthread&tid=31347&fromuid=23447
[体验篇二] ATSAMG53 Xplained Pro 获取资料
http://blog.sina.com.cn/s/blog_7e7fa4c80101k5v9.html
[体验篇三] ATSAMG53 Xplained Pro LED控制
http://blog.sina.com.cn/s/blog_7e7fa4c80101k6kw.html
在上一篇在大概 理解了,如何操作Atmel Studio ,如何下载程序,如何获取官方例程。今天主要任务是任务LED控制程序的原理。LED的控制,对于编程来说,就是引脚输出高低电平,就能控制LED的亮与灭,而LED 硬件的原理不在这篇之列,百度一下,有很多的说明。这里分析ATSAMG53 Xplained Pro 运行的代码的基本要点。
一、从int main(void) 开始
原代码如下:
#include
#include
#include
int main(void)
{
sysclk_init();
board_init();
while (true) {
for (int i = 0; i < 5; i++) {
gpio_toggle_pin(LED0_GPIO);
delay_s(1);
}
for (int i = 0; i < 50; i++) {
gpio_toggle_pin(LED0_GPIO);
delay_ms(100);
}
for (int i = 0; i < 5000; i++) {
gpio_toggle_pin(LED0_GPIO);
delay_us(100);
}
}
}
可以猜到,关键的初始化代码:
sysclk_init();// 系统时钟 初始化
board_init();// 系统硬件 初始化
二、分析 sysclk_init() 函数
其原代码
void sysclk_init(void)
{
system_init_flash(sysclk_get_cpu_hz());
if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_SLCK_RC) {
osc_enable(OSC_SLCK_32K_RC);
osc_wait_ready(OSC_SLCK_32K_RC);
pmc_switch_mck_to_sclk(CONFIG_SYSCLK_PRES);
}
else if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_SLCK_XTAL) {
osc_enable(OSC_SLCK_32K_XTAL);
osc_wait_ready(OSC_SLCK_32K_XTAL);
pmc_switch_mck_to_sclk(CONFIG_SYSCLK_PRES);
}
else if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_SLCK_BYPASS) {
osc_enable(OSC_SLCK_32K_BYPASS);
osc_wait_ready(OSC_SLCK_32K_BYPASS);
pmc_switch_mck_to_sclk(CONFIG_SYSCLK_PRES);
}
else if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_MAINCK_8M_RC) {
}
else if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_MAINCK_16M_RC) {
osc_enable(OSC_MAINCK_16M_RC);
osc_wait_ready(OSC_MAINCK_16M_RC);
pmc_switch_mck_to_mainck(CONFIG_SYSCLK_PRES);
}
else if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_MAINCK_24M_RC) {
osc_enable(OSC_MAINCK_24M_RC);
osc_wait_ready(OSC_MAINCK_24M_RC);
pmc_switch_mck_to_mainck(CONFIG_SYSCLK_PRES);
}
else if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_MAINCK_XTAL) {
osc_enable(OSC_MAINCK_XTAL);
osc_wait_ready(OSC_MAINCK_XTAL);
pmc_switch_mck_to_mainck(CONFIG_SYSCLK_PRES);
}
else if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_MAINCK_BYPASS) {
osc_enable(OSC_MAINCK_BYPASS);
osc_wait_ready(OSC_MAINCK_BYPASS);
pmc_switch_mck_to_mainck(CONFIG_SYSCLK_PRES);
}
#ifdef CONFIG_PLL0_SOURCE
else if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_PLLACK) {
struct pll_config pllcfg;
pll_enable_source(CONFIG_PLL0_SOURCE);
pll_config_defaults(&pllcfg, 0);
pll_enable(&pllcfg, 0);
pll_wait_for_lock(0);
pmc_switch_mck_to_pllack(CONFIG_SYSCLK_PRES);
}
#endif
SystemCoreClockUpdate();
#if (defined CONFIG_SYSCLK_DEFAULT_RETURNS_SLOW_OSC)
sysclk_initialized = 1;
#endif
}
分为三步
(1) Set a flash wait state depending on the new cpu frequency
(2) Config system clock setting
(3) Update the SystemFrequency variable
分析最二步,主要针对不同的时钟而进行不同的设置
SYSCLK_SRC_SLCK_RC
Internal 32kHz RC oscillator as master source clock
SYSCLK_SRC_SLCK_XTAL
External 32kHz crystal oscillator as master source clock
SYSCLK_SRC_SLCK_BYPASS
External 32kHz bypass oscillator as master source clock
SYSCLK_SRC_MAINCK_8M_RC
Internal 8MHz RC oscillator as master source clock
SYSCLK_SRC_MAINCK_16M_RC
Internal 16MHz RC oscillator as master source clock
SYSCLK_SRC_MAINCK_24M_RC
Internal 24MHz RC oscillator as master source clock
SYSCLK_SRC_MAINCK_XTAL
External crystal oscillator as master source clock
SYSCLK_SRC_MAINCK_BYPASS
External bypass oscillator as master source clock
SYSCLK_SRC_PLLACK
Use PLLACK as master source clock
感觉ATSAMG53的时钟源很丰富,确实时,再来看看以下两张图就明白ATSAMG53的时钟是如何设置,如下图所示:
源自 Atmel_11240_32-bit-Cortex-M4-Microcontroller_SAM-G53_Datasheet.pdf
分为SLCK MAINCK PLLCK 三种时钟源,选择后再进行分频选择。
关键的就是三句代码:
SLCK 与MAINCK 设置
osc_enable(....................);
osc_wait_ready(....................);
pmc_switch_mck_to_mainck(....................);
PLLCK 的设置(原因其自身倍频与分频设置: PLL0 (A) Options (Fpll = (Fclk * PLL_mul) / PLL_div))
pll_enable_source(CONFIG_PLL0_SOURCE); // 选择源 及倍频 分频的设置
pll_config_defaults(&pllcfg, 0);
pll_enable(&pllcfg, 0);
pll_wait_for_lock(0);
pmc_switch_mck_to_pllack(CONFIG_SYSCLK_PRES);
看上去,很复杂,但Atmel 公司已经为你想好,修改却非常的方便。
找到 conf_clock.h 文件进行修改时钟
// ===== System Clock (MCK) Source Options
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_SLCK_RC
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_SLCK_XTAL
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_SLCK_BYPASS
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_8M_RC
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_16M_RC
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_24M_RC
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_XTAL
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_BYPASS
#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_PLLACK
// ===== System Clock (MCK) Prescaler Options (Fmck = Fsys / (SYSCLK_PRES))
#define CONFIG_SYSCLK_PRES SYSCLK_PRES_1
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_2
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_4
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_8
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_16
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_32
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_64
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_3
// ===== PLL0 (A) Options (Fpll = (Fclk * PLL_mul) / PLL_div)
// Use mul and div effective values here.
#define CONFIG_PLL0_SOURCE PLL_SRC_SLCK_XTAL //External 32kHz crystal oscillator
//#define CONFIG_PLL0_SOURCE OSC_SLCK_32K_RC //Internal 32KHz RC oscillator.
#define CONFIG_PLL0_MUL 1465
#define CONFIG_PLL0_DIV 1
// ===== Target frequency (System clock)
// - External XTAL frequency: 32768Hz
// - System clock source: SLCK XTAL
// - System clock prescaler: 1 (divided by 1)
// - PLLA source: SLCK_XTAL
// - PLLA output: SLCK_XTAL * 1465 / 1
// - System clock: SLCK_XTAL * 1465 / 1 / 1 = 48MHz
上面的模板是使用 外部晶振 选择PLL作为 系统时钟源
PLL = SLCK_XTAL= 32768Hz *1465 / 1 = 48005120 = 48MHZ
系统时钟 = PLL /1 = 48MHZ
今天这篇写得比较长,明天再对board_init() 进行分析
三、分析board_init() board_init() 实际上是一些端口资源的初始化 在boar_init.c这文件中 #if defined(__GNUC__) void board_init(void) WEAK __attribute__((alias("system_board_init"))); #elif defined(__ICCARM__) void board_init(void); # pragma weak board_init=system_board_init #endif 通过weak 属性 (弱函数),然后将其绊定在void system_board_init(void) 这个函数中,这样的好处在于,如果用户新建一个void boar_init(void) 不会报错,并执行用户的函数,而不提用原来的void system_board_init(void)函数,如下图所示 现在来分析 void system_board_init(void) void system_board_init(void) { #ifndef CONF_BOARD_KEEP_WATCHDOG_AT_INIT WDT->WDT_MR = WDT_MR_WDDIS; //禁止看门狗 #endif ioport_init(); ioport_set_pin_dir(LED_0_PIN, IOPORT_DIR_OUTPUT); ioport_set_pin_level(LED_0_PIN, IOPORT_PIN_LEVEL_HIGH); ioport_set_pin_dir(BUTTON_0_PIN, IOPORT_DIR_INPUT); ioport_set_pin_mode(BUTTON_0_PIN, IOPORT_MODE_PULLUP); #if defined (CONF_BOARD_UART_CONSOLE) ioport_set_port_peripheral_mode(PINS_UART0_PORT, PINS_UART0, PINS_UART0_MASK); #endif #ifdef CONF_BOARD_USART_RXD ioport_set_pin_peripheral_mode(EXT1_PIN_UART_RX, IOPORT_MODE_MUX_A); #endif #ifdef CONF_BOARD_USART_TXD ioport_set_pin_peripheral_mode(EXT1_PIN_UART_TX, IOPORT_MODE_MUX_A); #endif #ifdef CONF_BOARD_USART_SCK ioport_set_pin_peripheral_mode(EXT3_PIN_10, IOPORT_MODE_MUX_B); #endif #if defined(CONF_BOARD_SPI) ioport_set_pin_peripheral_mode(SPI_MISO_GPIO, SPI_MISO_FLAGS); ioport_set_pin_peripheral_mode(SPI_MOSI_GPIO, SPI_MOSI_FLAGS); ioport_set_pin_peripheral_mode(SPI_SPCK_GPIO, SPI_SPCK_FLAGS); #ifdef CONF_BOARD_SPI_NPCS0 ioport_set_pin_peripheral_mode(SPI_NPCS0_GPIO, SPI_NPCS0_FLAGS); #endif #ifdef CONF_BOARD_SPI_NPCS1 ioport_set_pin_peripheral_mode(SPI_NPCS1_GPIO, SPI_NPCS1_FLAGS); #endif #endif #ifdef CONF_BOARD_TWI0 ioport_set_pin_peripheral_mode(TWI0_DATA_GPIO, TWI0_DATA_FLAGS); ioport_set_pin_peripheral_mode(TWI0_CLK_GPIO, TWI0_CLK_FLAGS); #endif #ifdef CONF_BOARD_TWI1 ioport_set_pin_peripheral_mode(TWI1_DATA_GPIO, TWI1_DATA_FLAGS); ioport_set_pin_peripheral_mode(TWI1_CLK_GPIO, TWI1_CLK_FLAGS); #endif #ifdef CONF_BOARD_TWI2 ioport_set_pin_peripheral_mode(TWI2_DATA_GPIO, TWI2_DATA_FLAGS); ioport_set_pin_peripheral_mode(TWI2_CLK_GPIO, TWI2_CLK_FLAGS); #endif #ifdef CONF_BOARD_I2S0 ioport_set_pin_peripheral_mode(I2S0_SCK_GPIO, I2S0_SCK_FLAGS); ioport_set_pin_peripheral_mode(I2S0_MCK_GPIO, I2S0_MCK_FLAGS); ioport_set_pin_peripheral_mode(I2S0_SDI_GPIO, I2S0_SDI_FLAGS); ioport_set_pin_peripheral_mode(I2S0_SDO_GPIO, I2S0_SDO_FLAGS); ioport_set_pin_peripheral_mode(I2S0_WS_GPIO, I2S0_WS_FLAGS); #endif #ifdef CONF_BOARD_I2S1 ioport_set_pin_peripheral_mode(I2S1_SCK_GPIO, I2S1_SCK_FLAGS); ioport_set_pin_peripheral_mode(I2S1_MCK_GPIO, I2S1_MCK_FLAGS); ioport_set_pin_peripheral_mode(I2S1_SDI_GPIO, I2S1_SDI_FLAGS); ioport_set_pin_peripheral_mode(I2S1_SDO_GPIO, I2S1_SDO_FLAGS); ioport_set_pin_peripheral_mode(I2S1_WS_GPIO, I2S1_WS_FLAGS); #endif } 其中关于LED的关键代码如下 ioport_set_pin_dir(LED_0_PIN, IOPORT_DIR_OUTPUT); ioport_set_pin_level(LED_0_PIN, IOPORT_PIN_LEVEL_HIGH); 可以在Atmel_11240_32-bit-Cortex-M4-Microcontroller_SAM-G53_Datasheet.pdf 第26章 Parallel Input/Output Controller (PIO) 这章,查到相关内容 Each I/O line of the PIO Controller features: l An input change interrupt enabling level change detection on any I/O line. l Additional Interrupt modes enabling rising edge, falling edge, low-level or high-level detection on any I/O line. l A glitch filter providing rejection of glitches lower than one-half of peripheral clock cycle. l A debouncing filter providing rejection of unwanted pulses from key or push button operations. l Multi-drive capability similar to an open drain I/O line. l Control of the pull-up and pull-down of the I/O line. l Input visibility and output control. 对应的寄存器 PIO_PER; PIO_PDR; PIO_PSR; ====================================================================== PIO_OER; PIO_ODR; PIO_OSR; ====================================================================== PIO_IFER; PIO_IFDR; PIO_IFSR; ====================================================================== PIO_SODR; PIO_CODR; PIO_ODSR; PIO_PDSR; PIO_IER; PIO_IDR; PIO_IMR; PIO_ISR; PIO_MDER; PIO_MDDR; PIO_MDSR; ====================================================================== PIO_PUDR; PIO_PUER; PIO_PUSR; ====================================================================== PIO_ABCDSR[2]; ====================================================================== PIO_IFSCDR; PIO_IFSCER; PIO_IFSCSR; PIO_SCDR; PIO_PPDDR; PIO_PPDER; PIO_PPDSR; ====================================================================== PIO_OWER; PIO_OWDR; PIO_OWSR; ====================================================================== PIO_AIMER; PIO_AIMDR; PIO_AIMMR; ======================================================================PIO_ESR; PIO_LSR; PIO_ELSR; ====================================================================== PIO_FELLSR; PIO_REHLSR; PIO_FRLHSR; ====================================================================== PIO_WPMR; PIO_WPSR; ====================================================================== PIO_SCHMITT; 我相信,记那么多的寄存器,烦都烦,建议,还是使用Atmel提供的函数方便一些,也方便易读 而对应的文件 是ioport.h 只要操作以下函数却可满足对应的功能 static inline void ioport_disable_pin(ioport_pin_t pin); static inline void ioport_disable_port(ioport_port_t port,ioport_port_mask_t mask); static inline void ioport_enable_pin(ioport_pin_t pin); static inline void ioport_enable_port(ioport_port_t port,ioport_port_mask_t mask); static inline bool ioport_get_pin_level(ioport_pin_t pin); static inline ioport_port_mask_t ioport_get_port_level(ioport_pin_t port,ioport_port_mask_t mask); static inline void ioport_init(void); static inline ioport_port_mask_t ioport_pin_to_mask(ioport_pin_t pin); static inline ioport_port_t ioport_pin_to_port_id(ioport_pin_t pin); static inline void ioport_reset_pin_mode(ioport_pin_t pin); static inline void ioport_reset_port_mode(ioport_port_t port,ioport_port_mask_t mask); static inline void ioport_set_pin_dir(ioport_pin_t pin,enum ioport_direction dir); static inline void ioport_set_pin_level(ioport_pin_t pin, bool level); static inline void ioport_set_pin_mode(ioport_pin_t pin, ioport_mode_t mode); static inline void ioport_set_pin_sense_mode(ioport_pin_t pin,enum ioport_sense pin_sense); static inline void ioport_set_port_dir(ioport_port_t port,ioport_port_mask_t mask, enum ioport_direction dir); static inline void ioport_set_port_level(ioport_port_t port,ioport_port_mask_t mask, ioport_port_mask_t level); static inline void ioport_set_port_mode(ioport_port_t port,ioport_port_mask_t mask, ioport_mode_t mode); static inline void ioport_set_port_sense_mode(ioport_port_t port,ioport_port_mask_t mask,enum ioport_sense pin_sense); static inline void ioport_toggle_pin_level(ioport_pin_t pin); static inline void ioport_toggle_port_level(ioport_port_t port,ioport_port_mask_t mask); 对于LED的操作以下这几函数即可满足功能 ioport_set_pin_dir(LED_0_PIN, IOPORT_DIR_OUTPUT); //设置为输出,默认为浮空 ioport_set_pin_level(LED_0_PIN, IOPORT_PIN_LEVEL_HIGH);//输出高电平 ioport_set_pin_level(LED_0_PIN, IOPORT_PIN_LEVEL_LOW);//输出低电平 ioport_toggle_pin_level(LED_0_PIN);// 电平返转 四、软件延时 delay_s(delay) Delay in seconds 秒 delay_ms(delay) Delay in milliseconds 微秒 delay_us(delay) Delay in microseconds 毫秒 三个函数,但实际上是统一调用void portable_delay_cycles(unsigned long n) 这个函数 关键代码 // Delay loop is put to SRAM so that FWS will not affect delay time OPTIMIZE_HIGH RAMFUNC void portable_delay_cycles(unsigned long n) { UNUSED(n); __asm ( "loop: DMB \n" "SUBS R0, R0, #1 \n" "BNE.N loop " ); } 它是复制到SRAM中执行,这样就没有有FWS 的延时,可以说这是一个比较准确的延时,其对于其他的厂家,有不用花时间或花资源去做个比较准确的延时函数。 在应用上直接用即可,但在delay.h 这文件中描述了一个函数 #define delay_init(fcpu_hz) 意思是在初始化时调用这个函数,虽然其函数实体没有什么作用,但还是在初始化系统参数时调用一下,为了结构的完整。 ==============================================================================================
可能转载的原因,有些图片打不开,如果有需要请移步以下地址,不想重新上传图片,时间有限不便之处请原谅!同时请大家多拍砖,可以到我博客去观看!
http://blog.sina.com.cn/s/blog_7e7fa4c80101k9ef.html
==============================================================================================
[体验篇一]ATSAMG53 Xplained Pro 开箱验货
https://www.cirmall.com/bbs/forum.php?mod=viewthread&tid=31347&fromuid=23447
[体验篇二] ATSAMG53 Xplained Pro 获取资料
http://blog.sina.com.cn/s/blog_7e7fa4c80101k5v9.html
[体验篇三] ATSAMG53 Xplained Pro LED控制
http://blog.sina.com.cn/s/blog_7e7fa4c80101k6kw.html
[体验篇四] ATSAMG53 Xplained Pro 分析LED控制
http://blog.sina.com.cn/s/blog_7e7fa4c80101k9ef.html
==============================================================================================
http://blog.sina.com.cn/s/blog_7e7fa4c80101k6kw.html
|