Renesas Synergy – pierwszy projekt w e2studio
Po automatycznym zainstalowaniu się sterownika J-Link można przejść do sprzętowego debugowania naszego programu migania diodami LED. Kiedy debugger J-link jest podłączony do komputera, to otwiera się automatycznie okno Segger J-Link Control panel – rysunek 15.
Rys. 15. Okno sterujące sprzętowego debuggera Segger J-Link
Debugowanie jest uruchamiane po kliknięciu na ikonkę przypominającą owada (rysunek 16) i wybraniu Debug As->Renesas GDB Hardware Debugging.
Rys. 16. Uruchamianie debugowania w środowisko e2studio
Debbuger programu e2studio działa podobnie jak w środowiskach IDE innych producentów. Do sterowania debugowaniem używa się następujących ikonek:
uruchom program
zatrzymaj program
zakończ debugowanie
odłącz proces debugowania
wykonanie jednego kroku programu z wejściem do funkcji
wykonanie całej funkcji
krok powrotu
debugowanie instrukcji assemblera
usuń wszystkie punkty zatrzymania (breakpoints)
zapisz program do pamięci
zeruj debugger
zeruj mikrokontroler (działanie programu)
odśwież
Po uruchomieniu debugowania automatycznie otwierają się okna: Debug, Project Explorer, okno z debugowanym kodem i Disassembly – rysunek 17. W oknie z debugowanym kodem będziemy oglądać wykonywanie programu napisanego w C, a w oknie Dissasembly kod w asemblerze.
Teraz możemy zobaczyć jak się wykonuje nasz kod z listingu 1. Program nie zatrzymuje się na wywołaniu procedury z funkcji main(), ale najpierw na procedurze funkcji Reset_Handler() – listing 3.
Rys. 17. Okna z debugowanym kodem
List. 3. Funkcja Reset_Handler
/********************************************************************************* * Function Name: Reset_Handler * Description : MCU starts executing here out of reset. Main stack pointer is setup already. * Arguments : none * Return Value : none *********************************************************************************/ void Reset_Handler (void) { /* Initialize system using BSP. */ SystemInit(); /* Call user application. */ main(); while (1) { /* Infinite Loop. */ } }
Jest to funkcja wywoływana po zerowaniu mikrokontrolera i dopiero ona wywołuje główna funkcję main(). Jednak zanim to nastąpi wywoływana jest funkcja System Init() umieszczona w pliku startup_S7G2.c i pokazana na listingu 4.
List. 4. Funkcja inicjalizacji mikrokontrolera
********************************************************************************* * Function Name: SystemInit * Description : Setup MCU. * Arguments : none * Return Value : none *********************************************************************************/ void SystemInit (void) { #if (defined (__GNUC__) && defined (__VFP_FP__) && !defined (__SOFTFP__)) || \ (defined (__ICCARM__) && defined (__ARMVFP__) && (__FPU_PRESENT == 1)) /* Enable the Cortex-M4 FPU only when -mfloat-abi=hard. Code taken from Section 7.1, Cortex-M4 TRM (DDI0439C) */ /* Set bits 20-23 to enable CP10 and CP11 coprocessor */ SCB->CPACR |= (0xF << 20); #endif /* Call Pre C runtime initialization hook. */ R_BSP_WarmStart(BSP_WARM_START_PRE_C); /* Initialize grouped interrupts. */ bsp_group_interrupt_open(); /* Configure system clocks using CGC module. */ bsp_clock_init(); /* Initialize register protection. */ bsp_register_protect_open(); /* Handle VBTICTLR register. */ bsp_vbatt_init(&g_bsp_pin_cfg); /* Initialize pins. */ g_ioport_on_ioport.init(&g_bsp_pin_cfg); /* Initialize C runtime environment. */ /* Zero out BSS */ #if defined(__GNUC__) bsp_section_zero((uint8_t *)&__bss_start__, ((uint32_t)&__bss_end__ - (uint32_t)&__bss_start__)); #elif defined(__ICCARM__) bsp_section_zero((uint8_t *)__section_begin(".bss"), (uint32_t)__section_size(".bss")); #endif /* Copy initialized RAM data from ROM to RAM. */ #if defined(__GNUC__) bsp_section_copy((uint8_t *)&__etext, (uint8_t *)&__data_start__, ((uint32_t)&__data_end__ - (uint32_t)&__data_start__)); #elif defined(__ICCARM__) bsp_section_copy((uint8_t *)__section_begin(".data_init"), (uint8_t *)__section_begin(".data"), (uint32_t)__section_size(".data")); /* Copy functions to be executed from RAM. */ #pragma section=".code_in_ram" #pragma section=".code_in_ram_init" bsp_section_copy((uint8_t *)__section_begin(".code_in_ram_init"), (uint8_t *)__section_begin(".code_in_ram"), (uint32_t)__section_size(".code_in_ram")); #endif /* Initialize SystemCoreClock variable. */ SystemCoreClock = bsp_cpu_clock_get(); /* Call Post C runtime initialization hook. */ R_BSP_WarmStart(BSP_WARM_START_POST_C); /* Initialize the Hardware locks to 'Unlocked' */ bsp_init_hardware_locks(); /* Initialize ELC events that will be used to trigger NVIC interrupts. */ bsp_irq_cfg(); /* Initialize ELC. */ g_elc_on_elc.init(&g_elc_cfg); /* Call any BSP specific code. No arguments are needed so NULL is sent. */ bsp_init(NULL); }
Zgodnie z przewidywaniami inicjalizacja jest dość rozbudowana i zawiera procedury ustawiające między innymi taktowanie, system przerwań, protekcję zapisu rejestrów, inicjowanie linii GPIO itp.
Każdą z funkcji inicjalizujących można w debugerze wykonywać krokowo i posiłkując się dokumentacją mikrokontrolera patrzeć jak postępuje konfigurowanie mikrokontrolera. Możemy jako przykład zobaczyć jak wygląda ustawianie taktowania mikrokontrolera wykonywane przez procedurę bsp_clock_init – listing 5.
List. 5. Konfigurowanie taktowania mikrokontrolera
/*********************************************************************************//** * @brief Sets up system clocks. *********************************************************************************/ void bsp_clock_init (void) { g_cgc_on_cgc.init(); /** MOCO is default clock out of reset. Enable new clock if chosen. */ cgc_clock_t clock; if (BSP_CFG_CLOCK_SOURCE != CGC_CLOCK_PLL) { clock = BSP_CFG_CLOCK_SOURCE; g_cgc_on_cgc.clockStart(clock, NULL); } else { /** Need to start PLL source clock and let it stabilize before starting PLL */ clock = BSP_CFG_PLL_SOURCE; g_cgc_on_cgc.clockStart(clock, NULL); cgc_clock_cfg_t pll_cfg; /** Set PLL Divider. */ pll_cfg.divider = BSP_CFG_PLL_DIV; /** Set PLL Multiplier. */ pll_cfg.multiplier = BSP_CFG_PLL_MUL; /** Set PLL Source clock. */ pll_cfg.source_clock = clock; while (SSP_ERR_STABILIZED != g_cgc_on_cgc.clockCheck(clock)) { /** Wait for PLL clock source to stabilize */ } g_cgc_on_cgc.clockStart(CGC_CLOCK_PLL, &pll_cfg); clock = CGC_CLOCK_PLL; } R_ROMC->ROMCE_b.ROMCEN = 1; /** Enable ROM cache */ /** MOCO, LOCO, and subclock do not have stabilization flags that can be checked. */ if ((CGC_CLOCK_MOCO != clock) && (CGC_CLOCK_LOCO != clock) && (CGC_CLOCK_SUBCLOCK != clock)) { while (SSP_ERR_STABILIZED != g_cgc_on_cgc.clockCheck(clock)) { /** Wait for clock source to stabilize */ } } cgc_system_clock_cfg_t sys_cfg; sys_cfg.iclk_div = BSP_CFG_ICK_DIV; sys_cfg.pclka_div = BSP_CFG_PCKA_DIV; sys_cfg.pclkb_div = BSP_CFG_PCKB_DIV; sys_cfg.pclkc_div = BSP_CFG_PCKC_DIV; sys_cfg.pclkd_div = BSP_CFG_PCKD_DIV; sys_cfg.fclk_div = BSP_CFG_FCK_DIV; sys_cfg.bclk_div = BSP_CFG_BCK_DIV; /** Set which clock to use for system clock and divisors for all system clocks. */ g_cgc_on_cgc.systemClockSet(clock, &sys_cfg); /** Set USB clock divisor. */ g_cgc_on_cgc.usbClockCfg(BSP_CFG_UCK_DIV); /** Configure BCLK */ #if BSP_CFG_BCLK_OUTPUT == 1 g_cgc_on_cgc.busClockOutCfg(CGC_BCLOCKOUT_DIV_1); g_cgc_on_cgc.busClockOutEnable(); #elif BSP_CFG_BCLK_OUTPUT == 2 g_cgc_on_cgc.busClockOutCfg(CGC_BCLOCKOUT_DIV_2); g_cgc_on_cgc.busClockOutEnable(); #else g_cgc_on_cgc.busClockOutDisable(); #endif /** Configure SDRAM Clock */ #if BSP_CFG_SDCLK_OUTPUT == 0 g_cgc_on_cgc.sdramClockOutDisable(); #else g_cgc_on_cgc.sdramClockOutEnable(); #endif }