This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

SPI doesn't work with bootloader

Hi,

I'm creating a simple SPI bootloader without SD for nRF51822 based on this post

The bootloader is connected to Freescale 22F through SPI and it will be without any BLE. The application itself is simple, which is only sending some SPI data back to 22F.

Here's the application:

int main(void)
{
    // Set 16 MHz crystal as our 16 MHz clock source (as opposed to internal RCOSC)
    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    NRF_CLOCK->TASKS_HFCLKSTART = 1;
    while(NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
    {
        // Wait
    }
	
	init_spi();
	
	while (true) {
		spi_tx.data = 123;
		spi_send(spi_tx);
		nrf_delay_us(10);
	}
}

IROM1: start = 0x2000, size = 0x39000 IRAM1: start = 0x20000000, size = 0x8000

The bootloader is also a simple one which will just take the application from 22F through SPI and then write the application into flash. Here's the bootloader code:

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

int main(void)
{
    // Set 16 MHz crystal as our 16 MHz clock source (as opposed to internal RCOSC)
    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    NRF_CLOCK->TASKS_HFCLKSTART = 1;
    while(NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
    {
        // Wait
    }
	init_spi();

#if 1
	int count = 200;
	while (true) {
		spi_tx.data = 234;
		spi_send(spi_tx);
		nrf_delay_us(10);
		count--;
		if(count <= 0) {
			bjump();    // jump #1
		}
	}
#endif
	
	bjump();    // jump #2
	
	init_bootloader();
		
    while (true)
    {   
		... main loop for bootloader communication with SPI

IROM1: start = 0x0, size = 0x1F00 IRAM1: start = 0x20000000, size = 0x8000

Currently, I put two debugging codes (bjump), one at location #1 and one at location #2. If I enabled the code at #1, the bootloading process will work properly. I.e., it will send the "234" data couple of times and then the data got changed to "123" which is coming from the application itself.

However, if I disabled the jump code at #1 and enabled the code at #2, only the "234" was received by 22F. After that, the application seems to stuck at some loop. When I ran the bootloader with debugger, I can see that it executed the jump command and then pass the PC to the application, but cannot debug further since I can only see the assembly code.

What could have I missed here?

Thanks, -- Steven

  • Hi Steven,

    I can see you move the MSP and the PC to the application, but I haven't seen you forward the vector table. Note that on Cortex M0 the vector table is fixed at 0x00000000. So you need to forward it manually.

    You can test simply blinking a LED in your application to see if it's forwarded correctly or not.

    You can find my code of forwarding the vector table in the case you quoted in your question (in interrupt_handler.c file)

  • Thanks, Hung Bui. That works! One followup question: Is there a way to blindly forward the vector table from 0x00000000 to the application without modifying the interrupt handler code in bootloader? I'm using the standard nRF libraries and drivers which already define interrupt handler (e.g., GPIOTE_IRQHandler code in app_gpiote.c). If I just redefine the GPIOTE_IRQHandler function in interrupt.c file, the compiler will complain about multiply defined GPIOTE_IRQHandler (which is true since I have two of them). To resolve this, I need to modify the GPIOTE_IRQHandler inside app_gpiote.c (rename it to GPIOTE_IRQHandler_Bootloader).

    It will be good if I can leave the library/driver files as it is.

    Thanks, -- Steven

  • Hi Stef,

    I assume you use the GPIOTE_IRQ handler in the bootloader. If you do, you would need to have branching, it's the same with the handlers in my bootloader example(SWI0_IRQHandler_Bootloader, RTC1_IRQHandler_Bootloader, UART0_IRQHandler_Bootloader, GPIOTE_IRQHandler_Bootloader).

    I think if you don't want to modify the driver's IRQ handler, what you can do is to modify the IRQ handler names in arm_startup_nrf51.s and then match the names accordingly in the interrupt_handler.c . This way you avoid declaring weak interrupt handler declare to for example GPIOTE_IRQHandler, and then use that in the driver files so you can keep file intact.

Related