Advertisement
Guest User

nRF51822 + s130 + bare minimum bootloader = works! :)

a guest
Mar 2nd, 2016
752
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.14 KB | None | 0 0
  1. #include <stdint.h>
  2. #include <string.h>
  3. #include <stddef.h>
  4. #include "ble.h"
  5. #include "nrf_sdm.h"
  6. #include "nrf_mbr.h"
  7. #include "nrf_log.h"
  8. #include "app_error.h"
  9. #include "app_uart.h"
  10. #include "softdevice_handler_appsh.h"
  11.  
  12. #define NRF_UICR_BASE                   0x10001000UL
  13. #define NRF_UICR_BOOT_START_ADDRESS     (NRF_UICR_BASE + 0x14)
  14. #define BOOTLOADER_REGION_START         0x0003C000
  15.  
  16. #define IRQ_ENABLED             0x01                    /**< Field identifying if an interrupt is enabled. */
  17. #define MAX_NUMBER_INTERRUPTS   32                      /**< Maximum number of interrupts available. */
  18.  
  19. #define MBR_SIZE (0x1000)
  20. #define SOFTDEVICE_INFO_STRUCT_OFFSET (0x2000)
  21. #define SD_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x08)
  22. #define SD_SIZE_GET(baseaddr) (*((uint32_t *) ((baseaddr) + SD_SIZE_OFFSET)))
  23. #define CODE_REGION_1_START             SD_SIZE_GET(MBR_SIZE)
  24.  
  25. uint32_t m_uicr_bootloader_start_address __attribute__((at(NRF_UICR_BOOT_START_ADDRESS))) = BOOTLOADER_REGION_START;
  26.  
  27. void uart_puts(char* s);
  28.  
  29. static void interrupts_disable(void)
  30. {
  31.     uint32_t interrupt_setting_mask;
  32.     uint32_t irq = 0; // We start from first interrupt, i.e. interrupt 0.
  33.  
  34.     // Fetch the current interrupt settings.
  35.     interrupt_setting_mask = NVIC->ISER[0];
  36.  
  37.     for (; irq < MAX_NUMBER_INTERRUPTS; irq++)
  38.     {
  39.         if (interrupt_setting_mask & (IRQ_ENABLED << irq))
  40.         {
  41.             // The interrupt was enabled, and hence disable it.
  42.             NVIC_DisableIRQ((IRQn_Type)irq);
  43.         }
  44.     }
  45. }
  46.  
  47. /**
  48.  * @brief Function for aborting current application/bootloader jump to to other app/bootloader.
  49.  *
  50.  * @details This functions will use the address provide to swap the stack pointer and then load
  51.  *          the address of the reset handler to be executed. It will check current system mode
  52.  *          (thread/handler) and if in thread mode it will reset into other application.
  53.  *          If in handler mode \ref isr_abort will be executed to ensure correct exit of handler
  54.  *          mode and jump into reset handler of other application.
  55.  *
  56.  * @param[in]  start_addr  Start address of other application. This address must point to the
  57.                initial stack pointer of the application.
  58.  *
  59.  * @note This function will never return but issue a reset into provided application.
  60.  */
  61. #if defined ( __CC_ARM )
  62. __asm static void bootloader_util_reset(uint32_t start_addr)
  63. {
  64.     LDR   R5, [R0]              ; Get App initial MSP for bootloader.
  65.     MSR   MSP, R5               ; Set the main stack pointer to the applications MSP.
  66.     LDR   R0, [R0, #0x04]       ; Load Reset handler into R0. This will be first argument to branch instruction (BX).
  67.  
  68.     MOVS  R4, #0xFF             ; Load ones to R4.
  69.     SXTB  R4, R4                ; Sign extend R4 to obtain 0xFFFFFFFF instead of 0xFF.
  70.     MRS   R5, IPSR              ; Load IPSR to R5 to check for handler or thread mode.
  71.     CMP   R5, #0x00             ; Compare, if 0 then we are in thread mode and can continue to reset handler of bootloader.
  72.     BNE   isr_abort             ; If not zero we need to exit current ISR and jump to reset handler of bootloader.
  73.  
  74.     MOV   LR, R4                ; Clear the link register and set to ones to ensure no return, R4 = 0xFFFFFFFF.
  75.     BX    R0                    ; Branch to reset handler of bootloader.
  76.  
  77. isr_abort
  78.                                 ; R4 contains ones from line above. Will be popped as R12 when exiting ISR (Cleaning up the registers).
  79.     MOV   R5, R4                ; Fill with ones before jumping to reset handling. We be popped as LR when exiting ISR. Ensures no return to application.
  80.     MOV   R6, R0                ; Move address of reset handler to R6. Will be popped as PC when exiting ISR. Ensures the reset handler will be executed when exist ISR.
  81.     MOVS  r7, #0x21             ; Move MSB reset value of xPSR to R7. Will be popped as xPSR when exiting ISR. xPSR is 0x21000000 thus MSB is 0x21.
  82.     REV   r7, r7                ; Reverse byte order to put 0x21 as MSB.
  83.     PUSH  {r4-r7}               ; Push everything to new stack to allow interrupt handler to fetch it on exiting the ISR.
  84.  
  85.     MOVS  R4, #0x00             ; Fill with zeros before jumping to reset handling. We be popped as R0 when exiting ISR (Cleaning up of the registers).
  86.     MOVS  R5, #0x00             ; Fill with zeros before jumping to reset handling. We be popped as R1 when exiting ISR (Cleaning up of the registers).
  87.     MOVS  R6, #0x00             ; Fill with zeros before jumping to reset handling. We be popped as R2 when exiting ISR (Cleaning up of the registers).
  88.     MOVS  R7, #0x00             ; Fill with zeros before jumping to reset handling. We be popped as R3 when exiting ISR (Cleaning up of the registers).
  89.     PUSH  {r4-r7}               ; Push zeros (R4-R7) to stack to prepare for exiting the interrupt routine.
  90.  
  91.     MOVS  R0, #0xF9             ; Move the execution return command into register, 0xFFFFFFF9.
  92.     SXTB  R0, R0                ; Sign extend R0 to obtain 0xFFFFFFF9 instead of 0xF9.
  93.     BX    R0                    ; No return - Handler mode will be exited. Stack will be popped and execution will continue in reset handler initializing other application.
  94.     ALIGN
  95. }
  96. #elif defined ( __GNUC__ )
  97. static inline void bootloader_util_reset(uint32_t start_addr)
  98. {
  99.     __asm volatile(
  100.         "ldr   r0, [%0]\t\n"            // Get App initial MSP for bootloader.
  101.         "msr   msp, r0\t\n"             // Set the main stack pointer to the applications MSP.
  102.         "ldr   r0, [%0, #0x04]\t\n"     // Load Reset handler into R0.
  103.  
  104.         "movs  r4, #0xFF\t\n"           // Move ones to R4.
  105.         "sxtb  r4, r4\t\n"              // Sign extend R4 to obtain 0xFFFFFFFF instead of 0xFF.
  106.  
  107.         "mrs   r5, IPSR\t\n"            // Load IPSR to R5 to check for handler or thread mode.
  108.         "cmp   r5, #0x00\t\n"           // Compare, if 0 then we are in thread mode and can continue to reset handler of bootloader.
  109.         "bne   isr_abort\t\n"           // If not zero we need to exit current ISR and jump to reset handler of bootloader.
  110.  
  111.         "mov   lr, r4\t\n"              // Clear the link register and set to ones to ensure no return.
  112.         "bx    r0\t\n"                  // Branch to reset handler of bootloader.
  113.  
  114.         "isr_abort:  \t\n"
  115.  
  116.         "mov   r5, r4\t\n"              // Fill with ones before jumping to reset handling. Will be popped as LR when exiting ISR. Ensures no return to application.
  117.         "mov   r6, r0\t\n"              // Move address of reset handler to R6. Will be popped as PC when exiting ISR. Ensures the reset handler will be executed when exist ISR.
  118.         "movs  r7, #0x21\t\n"           // Move MSB reset value of xPSR to R7. Will be popped as xPSR when exiting ISR. xPSR is 0x21000000 thus MSB is 0x21.
  119.         "rev   r7, r7\t\n"              // Reverse byte order to put 0x21 as MSB.
  120.         "push  {r4-r7}\t\n"             // Push everything to new stack to allow interrupt handler to fetch it on exiting the ISR.
  121.  
  122.         "movs  r4, #0x00\t\n"           // Fill with zeros before jumping to reset handling. We be popped as R0 when exiting ISR (Cleaning up of the registers).
  123.         "movs  r5, #0x00\t\n"           // Fill with zeros before jumping to reset handling. We be popped as R1 when exiting ISR (Cleaning up of the registers).
  124.         "movs  r6, #0x00\t\n"           // Fill with zeros before jumping to reset handling. We be popped as R2 when exiting ISR (Cleaning up of the registers).
  125.         "movs  r7, #0x00\t\n"           // Fill with zeros before jumping to reset handling. We be popped as R3 when exiting ISR (Cleaning up of the registers).
  126.         "push  {r4-r7}\t\n"             // Push zeros (R4-R7) to stack to prepare for exiting the interrupt routine.
  127.  
  128.         "movs  r0, #0xF9\t\n"           // Move the execution return command into register, 0xFFFFFFF9.
  129.         "sxtb  r0, r0\t\n"              // Sign extend R0 to obtain 0xFFFFFFF9 instead of 0xF9.
  130.         "bx    r0\t\n"                  // No return - Handler mode will be exited. Stack will be popped and execution will continue in reset handler initializing other application.
  131.         ".align\t\n"
  132.         :: "r" (start_addr)             // Argument list for the gcc assembly. start_addr is %0.
  133.         :  "r0", "r4", "r5", "r6", "r7" // List of register maintained manually.
  134.     );
  135. }
  136. #elif defined ( __ICCARM__ )
  137. static inline void bootloader_util_reset(uint32_t start_addr)
  138. {
  139.     asm("ldr   r5, [%0]\n"                    // Get App initial MSP for bootloader.
  140.         "msr   msp, r5\n"                     // Set the main stack pointer to the applications MSP.
  141.         "ldr   r0, [%0, #0x04]\n"             // Load Reset handler into R0.
  142.  
  143.         "movs  r4, #0x00\n"                   // Load zero into R4.
  144.         "mvns  r4, r4\n"                      // Invert R4 to ensure it contain ones.
  145.  
  146.         "mrs   r5, IPSR\n"                    // Load IPSR to R5 to check for handler or thread mode
  147.         "cmp   r5, #0x00\n"                   // Compare, if 0 then we are in thread mode and can continue to reset handler of bootloader.
  148.         "bne.n isr_abort\n"                   // If not zero we need to exit current ISR and jump to reset handler of bootloader.
  149.  
  150.         "mov   lr, r4\n"                      // Clear the link register and set to ones to ensure no return.
  151.         "bx    r0\n"                          // Branch to reset handler of bootloader.
  152.  
  153.         "isr_abort: \n"
  154.                                               // R4 contains ones from line above. We be popped as R12 when exiting ISR (Cleaning up the registers).
  155.         "mov   r5, r4\n"                      // Fill with ones before jumping to reset handling. Will be popped as LR when exiting ISR. Ensures no return to application.
  156.         "mov   r6, r0\n"                      // Move address of reset handler to R6. Will be popped as PC when exiting ISR. Ensures the reset handler will be executed when exist ISR.
  157.         "movs  r7, #0x21\n"                   // Move MSB reset value of xPSR to R7. Will be popped as xPSR when exiting ISR. xPSR is 0x21000000 thus MSB is 0x21.
  158.         "rev   r7, r7\n"                      // Reverse byte order to put 0x21 as MSB.
  159.         "push  {r4-r7}\n"                     // Push everything to new stack to allow interrupt handler to fetch it on exiting the ISR.
  160.  
  161.         "movs  r4, #0x00\n"                   // Fill with zeros before jumping to reset handling. We be popped as R0 when exiting ISR (Cleaning up of the registers).
  162.         "movs  r5, #0x00\n"                   // Fill with zeros before jumping to reset handling. We be popped as R1 when exiting ISR (Cleaning up of the registers).
  163.         "movs  r6, #0x00\n"                   // Fill with zeros before jumping to reset handling. We be popped as R2 when exiting ISR (Cleaning up of the registers).
  164.         "movs  r7, #0x00\n"                   // Fill with zeros before jumping to reset handling. We be popped as R3 when exiting ISR (Cleaning up of the registers).
  165.         "push  {r4-r7}\n"                     // Push zeros (R4-R7) to stack to prepare for exiting the interrupt routine.
  166.  
  167.         "movs  r0, #0x06\n"                   // Load 0x06 into R6 to prepare for exec return command.
  168.         "mvns  r0, r0\n"                      // Invert 0x06 to obtain EXEC_RETURN, 0xFFFFFFF9.
  169.         "bx    r0\n"                          // No return - Handler mode will be exited. Stack will be popped and execution will continue in reset handler initializing other application.
  170.         :: "r" (start_addr)                   // Argument list for the IAR assembly. start_addr is %0.
  171.         :  "r0", "r4", "r5", "r6", "r7");     // List of register maintained manually.
  172. }
  173. #else
  174. #error Compiler not supported.
  175. #endif
  176.  
  177. int main(void)
  178. {
  179.     sd_mbr_command_t com = {SD_MBR_COMMAND_INIT_SD, };
  180.  
  181.         uint32_t err_code = sd_mbr_command(&com);
  182.         APP_ERROR_CHECK(err_code);
  183.    
  184.     interrupts_disable();
  185.  
  186.         uint32_t debug_code_addr_val = CODE_REGION_1_START; // debug_code_addr_val == 0x0001B000 , i.e. all correct here!
  187.         sd_softdevice_vector_table_base_set(debug_code_addr_val); // falls to SVC_Handler at 0x0003C1D2 here :(
  188.  
  189.     bootloader_util_reset(CODE_REGION_1_START);
  190. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement