This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

How to make the Nrf51822 flash jump successful without Softdevice?

Hi everyone, I trying to make a flash jump on Nrf51822 in my project. there are 2 programs(program A and program B) below. i am working on to make program A jump to program B correctly.

my problem is in my applications, program A can jump to program B, but the time0 interrupt doesn't works correctly.

in the program A led red and blue blink, and program B led green and yellow blinks, but when program A jumps to B, there are led yellow and red blink, it supposed to led green and yellow blinks. led red still blink , not led green. so i think something wrong with my interrupt operates.

is the VIC not operate right? in ARM7 i can do this

How can i make the interrupts works right in my case. where am i wrong?

program A and B shows below.

program A put at address 0x00000000, here it is:

  #define AppStartAddr       0x00010000

 void Configure_System_Clock( void )
 {
        // Start 16 MHz crystal oscillator.
        NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
        NRF_CLOCK->TASKS_HFCLKSTART    = 1;
    
        // Wait for the external oscillator to start up.
        while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) 
        {
            // Do nothing.
        }	   
}
    
void Init_Timer0( unsigned int TimerInterval ) 
{ 	  NRF_TIMER0->TASKS_STOP     = 1;        // stop the task first
    	
        NRF_TIMER0->MODE           = TIMER_MODE_MODE_Timer;        // Set the timer in Timer Mode.
        NRF_TIMER0->PRESCALER      = 1;                            // Prescaler 1 produces 8MHz timer frequency => 1 tick = 0.125 us.
        NRF_TIMER0->BITMODE        = TIMER_BITMODE_BITMODE_32Bit;  // 32 bit mode.
        NRF_TIMER0->TASKS_CLEAR    = 1;                            // clear the task first to be usable for later.
    
        NRF_TIMER0->CC[0]          = TimerInterval;  
        NRF_TIMER0->INTENCLR       = 0xFFFFFFFFUL;	 	 
        NRF_TIMER0->INTENSET  = ( TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos );
    
        NRF_TIMER0->TASKS_START    = 1;                    // Start timer.	
    	
        NVIC_ClearPendingIRQ(TIMER0_IRQn);
        NVIC_SetPriority(TIMER0_IRQn, 3);
        NVIC_EnableIRQ(TIMER0_IRQn);	 
}

void Init_WatchDog( void )
{
	  NRF_WDT->CRV           = WATCHDOG_TIMING_3s;
	  NRF_WDT->RREN	         = ( WDT_RREN_RR0_Enabled << WDT_RREN_RR0_Pos );
		while(NRF_WDT->REQSTATUS == 0U) // Wait for RR[0] START
		{
				// Do nothing.
		}	
	  NRF_WDT->TASKS_START   = 1;
		while(NRF_WDT->RUNSTATUS == 0U) // Wait for watchdog running
		{
				// Do nothing.
		}		
	  NRF_WDT->RR[0]         = WDT_RR_RR_Reload;	  
}

void WDTFeed( void )
{
	  NRF_WDT->RR[0]         = WDT_RR_RR_Reload;	  
}

__asm void StartApplication(uint32_t start_addr)
{
    LDR   R2, [R0]               ; Get App MSP.
    MSR   MSP, R2                ; Set the main stack pointer to the applications MSP.
    LDR   R3, [R0, #0x00000004]  ; Get application reset vector address.
    BX    R3                     ; No return - stack code is now activated only through SVC and plain interrupts.
    ALIGN
}

/**
 * @brief Function for application main entry.
 */
int main(void)
{
    Configure_System_Clock();
	 
    Init_GPIO();
	  Init_Timer0( TIME_INTERVAL_10ms );
		
    while(true)
    {
			  LED_BLUE_BLINK; // led blue blink
              nrf_delay_ms( 500 );			
		      IapWaitTime++;
			  if( IapWaitTime >= 20 ) 
				{
					  IapWaitTime = 0;				
                      StartApplication(AppStartAddr);					
				}   
    }   

}

void TIMER0_IRQHandler(void)
{	        
    Flag_counter_10ms++;
    
    if( Flag_counter_10ms == 100 )
    {
        Flag_counter_10ms = 0;
			  LED_RED_BLINK;  // led red blink
    }	
	
	  NRF_TIMER0->TASKS_CLEAR    = 1;                    // clear the task
	  NRF_TIMER0->EVENTS_COMPARE[0]    = 0;              // clear the event
	  NRF_TIMER0->TASKS_START    = 1;                    // Start timer.
}   //  */
/** @} */

program B put at address 0x00010000, here it is:

#define AppStartAddr1      0x00000000

void Configure_System_Clock( void )
{
    // Start 16 MHz crystal oscillator.
    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    NRF_CLOCK->TASKS_HFCLKSTART    = 1;

    // Wait for the external oscillator to start up.
    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) 
    {
        // Do nothing.
    }	  
}

void Init_Timer0( unsigned int TimerInterval )
{
	  NVIC_DisableIRQ(TIMER0_IRQn);
	  NRF_TIMER0->TASKS_STOP     = 1;                            // stop the task first
	
    NRF_TIMER0->MODE           = TIMER_MODE_MODE_Timer;        // Set the timer in Timer Mode.
    NRF_TIMER0->PRESCALER      = 1;                            // Prescaler 1 produces 8MHz timer frequency => 1 tick = 0.125 us.
    NRF_TIMER0->BITMODE        = TIMER_BITMODE_BITMODE_32Bit;  // 32 bit mode.
    NRF_TIMER0->TASKS_CLEAR    = 1;                            // clear the task first to be usable for later.

    NRF_TIMER0->CC[0]          = TimerInterval;  
    NRF_TIMER0->INTENCLR       = 0xFFFFFFFFUL;	
	  NRF_TIMER0->INTENSET       = ( TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos );

    NRF_TIMER0->TASKS_START    = 1;                    // Start timer.	
	
    NVIC_ClearPendingIRQ(TIMER0_IRQn);
    NVIC_SetPriority(TIMER0_IRQn, 3);
    NVIC_EnableIRQ(TIMER0_IRQn);	
}

void Init_GPIO( void )
{
    nrf_gpio_cfg_output(LED_RED);
	  nrf_gpio_cfg_output(LED_BLUE);
	  nrf_gpio_cfg_output(LED_GREEN);
	  nrf_gpio_cfg_output(LED_YELLOW);
	  nrf_gpio_cfg_output(MODE_DETECTIVE);
}

void Init_WatchDog( void )
{
	  NRF_WDT->CRV           = WATCHDOG_TIMING_3s;
	  NRF_WDT->RREN	         = ( WDT_RREN_RR0_Enabled << WDT_RREN_RR0_Pos );
		while(NRF_WDT->REQSTATUS == 0U) // Wait for RR[0] START
		{
				// Do nothing.
		}	
	  NRF_WDT->TASKS_START   = 1;
		while(NRF_WDT->RUNSTATUS == 0U) // Wait for watchdog running
		{
				// Do nothing.
		}		
	  NRF_WDT->RR[0]         = WDT_RR_RR_Reload;	  
}

void WDTFeed( void )
{
	  NRF_WDT->RR[0]         = WDT_RR_RR_Reload;	  
}

__asm void StartApplication(uint32_t start_addr)
{
    LDR   R2, [R0]               ; Get App MSP.
    MSR   MSP, R2                ; Set the main stack pointer to the applications MSP.
    LDR   R3, [R0, #0x00000004]  ; Get application reset vector address.
    BX    R3                     ; No return - stack code is now activated only through SVC and plain interrupts.
    ALIGN
}

/**
 * @brief Function for application main entry.
 */
int main(void)
{
    Configure_System_Clock();
    Init_GPIO();
	
	  Init_WatchDog();
	  Init_Timer0( TIME_INTERVAL_10ms );
	
    while(true)
    {  
			  WDTFeed();  
			
			  LED_YELLOW_BLINK;  // led yellow blink
        nrf_delay_ms( 500 );			
  
				IapWaitTime++;
			  if( IapWaitTime >= 20 )  
				{
					  IapWaitTime = 0;				
					   StartApplication(AppStartAddr1);
				}   
    }   

}

void TIMER0_IRQHandler(void)
{	       
    Flag_counter_10ms++;
    
    if( Flag_counter_10ms == 100 )
    {
        Flag_counter_10ms = 0;
			  LED_GREEN_BLINK;  // led green blink
    }	 
	
	  NRF_TIMER0->TASKS_CLEAR    = 1;                    // clear the task
	  NRF_TIMER0->EVENTS_COMPARE[0]    = 0;              // clear the event
	  NRF_TIMER0->TASKS_START    = 1;                    // Start timer.
}
/** @} */
  • Hi lanxiang,

    You would need to forward the interrupts (vector table) from Program A to program B when you switch to program B.

    One solution is to use a flag to switch between 2 programs when calling the interrupt handler.

    You can have a look at the attached bootloader without softdevice, where we check for bootloader_active flag to decide if we should call the interrupt handler in bootloader or in application. Please have a look at the interrupt_handler.c file.

    The example's pretty old though.

    nrf51822_v4.4 - Bootloader_Without_SD.zip

  • Hi Hung Bui

    I'm using interrupt_handler.c for a bootloader without a softdevice. Interrupt handling in the main app seems to work fine. But interrupts in the bootloader leading to a reset.

    For example my uart interrupt.

    1. on an uart interrupt section bootloop is called
    2. jumps to uart0
    3. jumps to execute
    4. execute jumps to 0x0000 0000

    Why?

    [uart.c]
    void UART0_IRQHandler_Bootloader(void)
    {
        // some code
    }
    
    
    [interrupt_handler.c]
    bootload 
            CMP R0, #0x24;
            BEQ swi0
            CMP R0, #0x21;
            BEQ rtc1
            CMP R0, #0x16;
            BEQ gpiote
            CMP R0, #0x12;
            BEQ uart0
            //RETURN code needed
    uart0
            EXTERN  UART0_IRQHandler_Bootloader[WEAK]     
            LDR    R0,=UART0_IRQHandler_Bootloader
            B execute ;            
    execute            
            BX     R0  ;
    
  • @bvrm: Please create a new question, instead of posting a question as an answer. In your new question please add information on:

    • Would you have problem when testing with my bootloader example in the .zip file ?

    • What do you have in R0 when you LDR R0,=UART0_IRQHandler_Bootloader ?

  • Thats probably because you do not have UART0_IRQHandler_Bootloader defined. Make sure that your bootloader UART0 interrupt handler is named with the same name as you are refering here which is void UART0_IRQHandler_Bootloader(void)

  • I did some investigations: R0 is loaded with 0x0000 0000 is above example. When removing [WEAK] everything works as expected. Leaving [WEAK] linker (Keil 5.14) is removing UART0_IRQHandler_Bootloader section.

    Removing Unused input sections from the image.
    
        Removing main.o(.rev16_text), (4 bytes).
        Removing main.o(.revsh_text), (4 bytes).
        Removing main.o(i.init), (60 bytes).
        Removing uartreader.o(.rev16_text), (4 bytes).
        Removing uartreader.o(.revsh_text), (4 bytes).
        Removing uartreader.o(i.UART0_IRQHandler_Bootloader), (140 bytes).
        Removing uartreader.o(.bss), (50 bytes).
        Removing arm_startup_nrf51.o(HEAP), (1024 bytes).
        Removing system_nrf51.o(.rev16_text), (4 bytes).
        Removing system_nrf51.o(.revsh_text), (4 bytes).
        Removing system_nrf51.o(i.SystemCoreClockUpdate), (16 bytes).
    
    11 unused section(s) (total 1314 bytes) removed from the image.
    
Related