Advertisement
Guest User

nRF51822 bare minimum bootloader (doesn't work)

a guest
Mar 2nd, 2016
334
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.30 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 "nrf_delay.h"
  9. #include "nrf_drv_uart.h"
  10. #include "app_error.h"
  11. #include "app_uart.h"
  12. #include "softdevice_handler_appsh.h"
  13.  
  14. #define IS_SRVC_CHANGED_CHARACT_PRESENT 1  
  15.  
  16. #define NRF_UICR_BASE                   0x10001000UL
  17. #define NRF_UICR_BOOT_START_ADDRESS     (NRF_UICR_BASE + 0x14)
  18. #define BOOTLOADER_REGION_START         0x0003C000
  19.  
  20. #define IRQ_ENABLED             0x01                    /**< Field identifying if an interrupt is enabled. */
  21. #define MAX_NUMBER_INTERRUPTS   32                      /**< Maximum number of interrupts available. */
  22.  
  23. #define MBR_SIZE (0x1000)
  24. #define SOFTDEVICE_INFO_STRUCT_OFFSET (0x2000)
  25. #define SD_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x08)
  26. #define SD_SIZE_GET(baseaddr) (*((uint32_t *) ((baseaddr) + SD_SIZE_OFFSET)))
  27. #define CODE_REGION_1_START             SD_SIZE_GET(MBR_SIZE)
  28. #define DFU_BANK_0_REGION_START         CODE_REGION_1_START
  29.  
  30. uint32_t m_uicr_bootloader_start_address __attribute__((at(NRF_UICR_BOOT_START_ADDRESS))) = BOOTLOADER_REGION_START;
  31.  
  32. void uart_puts(char* s);
  33.  
  34. static void interrupts_disable(void)
  35. {
  36.     uint32_t interrupt_setting_mask;
  37.     uint32_t irq = 0; // We start from first interrupt, i.e. interrupt 0.
  38.  
  39.     // Fetch the current interrupt settings.
  40.     interrupt_setting_mask = NVIC->ISER[0];
  41.  
  42.     for (; irq < MAX_NUMBER_INTERRUPTS; irq++)
  43.     {
  44.         if (interrupt_setting_mask & (IRQ_ENABLED << irq))
  45.         {
  46.             // The interrupt was enabled, and hence disable it.
  47.             NVIC_DisableIRQ((IRQn_Type)irq);
  48.         }
  49.     }
  50. }
  51.  
  52. /**
  53.  * @brief Function for aborting current application/bootloader jump to to other app/bootloader.
  54.  *
  55.  * @details This functions will use the address provide to swap the stack pointer and then load
  56.  *          the address of the reset handler to be executed. It will check current system mode
  57.  *          (thread/handler) and if in thread mode it will reset into other application.
  58.  *          If in handler mode \ref isr_abort will be executed to ensure correct exit of handler
  59.  *          mode and jump into reset handler of other application.
  60.  *
  61.  * @param[in]  start_addr  Start address of other application. This address must point to the
  62.                initial stack pointer of the application.
  63.  *
  64.  * @note This function will never return but issue a reset into provided application.
  65.  */
  66. #if defined ( __CC_ARM )
  67. __asm static void bootloader_util_reset(uint32_t start_addr)
  68. {
  69.     LDR   R5, [R0]              ; Get App initial MSP for bootloader.
  70.     MSR   MSP, R5               ; Set the main stack pointer to the applications MSP.
  71.     LDR   R0, [R0, #0x04]       ; Load Reset handler into R0. This will be first argument to branch instruction (BX).
  72.  
  73.     MOVS  R4, #0xFF             ; Load ones to R4.
  74.     SXTB  R4, R4                ; Sign extend R4 to obtain 0xFFFFFFFF instead of 0xFF.
  75.     MRS   R5, IPSR              ; Load IPSR to R5 to check for handler or thread mode.
  76.     CMP   R5, #0x00             ; Compare, if 0 then we are in thread mode and can continue to reset handler of bootloader.
  77.     BNE   isr_abort             ; If not zero we need to exit current ISR and jump to reset handler of bootloader.
  78.  
  79.     MOV   LR, R4                ; Clear the link register and set to ones to ensure no return, R4 = 0xFFFFFFFF.
  80.     BX    R0                    ; Branch to reset handler of bootloader.
  81.  
  82. isr_abort
  83.                                 ; R4 contains ones from line above. Will be popped as R12 when exiting ISR (Cleaning up the registers).
  84.     MOV   R5, R4                ; Fill with ones before jumping to reset handling. We be popped as LR when exiting ISR. Ensures no return to application.
  85.     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.
  86.     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.
  87.     REV   r7, r7                ; Reverse byte order to put 0x21 as MSB.
  88.     PUSH  {r4-r7}               ; Push everything to new stack to allow interrupt handler to fetch it on exiting the ISR.
  89.  
  90.     MOVS  R4, #0x00             ; Fill with zeros before jumping to reset handling. We be popped as R0 when exiting ISR (Cleaning up of the registers).
  91.     MOVS  R5, #0x00             ; Fill with zeros before jumping to reset handling. We be popped as R1 when exiting ISR (Cleaning up of the registers).
  92.     MOVS  R6, #0x00             ; Fill with zeros before jumping to reset handling. We be popped as R2 when exiting ISR (Cleaning up of the registers).
  93.     MOVS  R7, #0x00             ; Fill with zeros before jumping to reset handling. We be popped as R3 when exiting ISR (Cleaning up of the registers).
  94.     PUSH  {r4-r7}               ; Push zeros (R4-R7) to stack to prepare for exiting the interrupt routine.
  95.  
  96.     MOVS  R0, #0xF9             ; Move the execution return command into register, 0xFFFFFFF9.
  97.     SXTB  R0, R0                ; Sign extend R0 to obtain 0xFFFFFFF9 instead of 0xF9.
  98.     BX    R0                    ; No return - Handler mode will be exited. Stack will be popped and execution will continue in reset handler initializing other application.
  99.     ALIGN
  100. }
  101. #elif defined ( __GNUC__ )
  102. static inline void bootloader_util_reset(uint32_t start_addr)
  103. {
  104.     __asm volatile(
  105.         "ldr   r0, [%0]\t\n"            // Get App initial MSP for bootloader.
  106.         "msr   msp, r0\t\n"             // Set the main stack pointer to the applications MSP.
  107.         "ldr   r0, [%0, #0x04]\t\n"     // Load Reset handler into R0.
  108.  
  109.         "movs  r4, #0xFF\t\n"           // Move ones to R4.
  110.         "sxtb  r4, r4\t\n"              // Sign extend R4 to obtain 0xFFFFFFFF instead of 0xFF.
  111.  
  112.         "mrs   r5, IPSR\t\n"            // Load IPSR to R5 to check for handler or thread mode.
  113.         "cmp   r5, #0x00\t\n"           // Compare, if 0 then we are in thread mode and can continue to reset handler of bootloader.
  114.         "bne   isr_abort\t\n"           // If not zero we need to exit current ISR and jump to reset handler of bootloader.
  115.  
  116.         "mov   lr, r4\t\n"              // Clear the link register and set to ones to ensure no return.
  117.         "bx    r0\t\n"                  // Branch to reset handler of bootloader.
  118.  
  119.         "isr_abort:  \t\n"
  120.  
  121.         "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.
  122.         "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.
  123.         "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.
  124.         "rev   r7, r7\t\n"              // Reverse byte order to put 0x21 as MSB.
  125.         "push  {r4-r7}\t\n"             // Push everything to new stack to allow interrupt handler to fetch it on exiting the ISR.
  126.  
  127.         "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).
  128.         "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).
  129.         "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).
  130.         "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).
  131.         "push  {r4-r7}\t\n"             // Push zeros (R4-R7) to stack to prepare for exiting the interrupt routine.
  132.  
  133.         "movs  r0, #0xF9\t\n"           // Move the execution return command into register, 0xFFFFFFF9.
  134.         "sxtb  r0, r0\t\n"              // Sign extend R0 to obtain 0xFFFFFFF9 instead of 0xF9.
  135.         "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.
  136.         ".align\t\n"
  137.         :: "r" (start_addr)             // Argument list for the gcc assembly. start_addr is %0.
  138.         :  "r0", "r4", "r5", "r6", "r7" // List of register maintained manually.
  139.     );
  140. }
  141. #elif defined ( __ICCARM__ )
  142. static inline void bootloader_util_reset(uint32_t start_addr)
  143. {
  144.     asm("ldr   r5, [%0]\n"                    // Get App initial MSP for bootloader.
  145.         "msr   msp, r5\n"                     // Set the main stack pointer to the applications MSP.
  146.         "ldr   r0, [%0, #0x04]\n"             // Load Reset handler into R0.
  147.  
  148.         "movs  r4, #0x00\n"                   // Load zero into R4.
  149.         "mvns  r4, r4\n"                      // Invert R4 to ensure it contain ones.
  150.  
  151.         "mrs   r5, IPSR\n"                    // Load IPSR to R5 to check for handler or thread mode
  152.         "cmp   r5, #0x00\n"                   // Compare, if 0 then we are in thread mode and can continue to reset handler of bootloader.
  153.         "bne.n isr_abort\n"                   // If not zero we need to exit current ISR and jump to reset handler of bootloader.
  154.  
  155.         "mov   lr, r4\n"                      // Clear the link register and set to ones to ensure no return.
  156.         "bx    r0\n"                          // Branch to reset handler of bootloader.
  157.  
  158.         "isr_abort: \n"
  159.                                               // R4 contains ones from line above. We be popped as R12 when exiting ISR (Cleaning up the registers).
  160.         "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.
  161.         "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.
  162.         "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.
  163.         "rev   r7, r7\n"                      // Reverse byte order to put 0x21 as MSB.
  164.         "push  {r4-r7}\n"                     // Push everything to new stack to allow interrupt handler to fetch it on exiting the ISR.
  165.  
  166.         "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).
  167.         "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).
  168.         "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).
  169.         "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).
  170.         "push  {r4-r7}\n"                     // Push zeros (R4-R7) to stack to prepare for exiting the interrupt routine.
  171.  
  172.         "movs  r0, #0x06\n"                   // Load 0x06 into R6 to prepare for exec return command.
  173.         "mvns  r0, r0\n"                      // Invert 0x06 to obtain EXEC_RETURN, 0xFFFFFFF9.
  174.         "bx    r0\n"                          // No return - Handler mode will be exited. Stack will be popped and execution will continue in reset handler initializing other application.
  175.         :: "r" (start_addr)                   // Argument list for the IAR assembly. start_addr is %0.
  176.         :  "r0", "r4", "r5", "r6", "r7");     // List of register maintained manually.
  177. }
  178. #else
  179. #error Compiler not supported.
  180. #endif
  181.  
  182. void bootloader_util_app_start(uint32_t start_addr)
  183. {
  184.     bootloader_util_reset(start_addr);
  185. }
  186.  
  187. void bootloader_app_start(uint32_t app_addr)
  188. {
  189.     // If the applications CRC has been checked and passed, the magic number will be written and we
  190.     // can start the application safely.
  191.     uint32_t err_code = sd_softdevice_disable();
  192.     APP_ERROR_CHECK(err_code);
  193.  
  194.     interrupts_disable();
  195.  
  196.     err_code = sd_softdevice_vector_table_base_set(CODE_REGION_1_START);
  197.     APP_ERROR_CHECK(err_code);
  198.  
  199.     bootloader_util_app_start(CODE_REGION_1_START);
  200. }
  201.  
  202. void uart_evt_callback(app_uart_evt_t * uart_evt)
  203. {
  204.         uint8_t ch;
  205.    
  206.     switch (uart_evt->evt_type)
  207.     {
  208.         case APP_UART_DATA:
  209.                         //Data is ready on the UART
  210.             break;
  211.                        
  212.                 case APP_UART_DATA_READY:
  213.             //Data is ready on the UART FIFO
  214.                         app_uart_get(&ch);
  215.                         //app_uart_put(ch); // echo
  216.  
  217.                         if(ch == 'h')
  218.                         {
  219.                             uart_puts("\
  220. \n\
  221. help:\n\
  222. h - this help.\n\
  223. s - start app at bank0.\n");
  224.                         } else if(ch == 's') {
  225.                             bootloader_app_start(DFU_BANK_0_REGION_START);
  226.                             NVIC_SystemReset();
  227.                         }
  228.  
  229.             break;
  230.                        
  231.         case APP_UART_TX_EMPTY:
  232.                         //Data has been successfully transmitted on the UART
  233.             break;
  234.                        
  235.         default:
  236.             break;
  237.     }
  238. }
  239.  
  240. void uart_init(void)
  241. {
  242.     uint32_t err_code;
  243.    
  244.     const app_uart_comm_params_t comm_params =
  245.     {
  246.             11, // RX_PIN_NUMBER,
  247.              9, //TX_PIN_NUMBER,
  248.             10, //RTS_PIN_NUMBER,
  249.              8, //CTS_PIN_NUMBER,
  250.             APP_UART_FLOW_CONTROL_DISABLED,
  251.             false,
  252.             UART_BAUDRATE_BAUDRATE_Baud115200
  253.     };
  254.    
  255.     APP_UART_FIFO_INIT(&comm_params,
  256.                                 1, // RX buf
  257.                                 256, // TX buf
  258.                                 uart_evt_callback,
  259.                                 APP_IRQ_PRIORITY_HIGH,
  260.                                 err_code);
  261.    
  262.     APP_ERROR_CHECK(err_code);
  263. }
  264.  
  265. void uart_puts(char* s)
  266. {
  267.     while(*s){
  268.         app_uart_put(*s++);
  269.         nrf_delay_ms(1);
  270.     }
  271. }
  272.  
  273. static void sys_evt_dispatch(uint32_t event)
  274. {
  275.     //pstorage_sys_event_handler(event);
  276. }
  277.  
  278. /**@brief Function for initializing the BLE stack.
  279.  *
  280.  * @details Initializes the SoftDevice and the BLE event interrupt.
  281.  *
  282.  * @param[in] init_softdevice  true if SoftDevice should be initialized. The SoftDevice must only
  283.  *                             be initialized if a chip reset has occured. Soft reset from
  284.  *                             application must not reinitialize the SoftDevice.
  285.  */
  286. static void ble_stack_init(bool init_softdevice)
  287. {
  288.     uint32_t         err_code;
  289.     sd_mbr_command_t com = {SD_MBR_COMMAND_INIT_SD, };
  290.  
  291.     if (init_softdevice)
  292.     {
  293.         err_code = sd_mbr_command(&com);
  294.         APP_ERROR_CHECK(err_code);
  295.     }
  296.    
  297.     err_code = sd_softdevice_vector_table_base_set(BOOTLOADER_REGION_START);
  298.     APP_ERROR_CHECK(err_code);
  299.    
  300.     SOFTDEVICE_HANDLER_APPSH_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, true);
  301.  
  302.     // Enable BLE stack.
  303.     ble_enable_params_t ble_enable_params;
  304.     // Only one connection as a central is used when performing dfu.
  305.     err_code = softdevice_enable_get_default_config(1, 1, &ble_enable_params);
  306.     APP_ERROR_CHECK(err_code);
  307.  
  308.     ble_enable_params.gatts_enable_params.service_changed = IS_SRVC_CHANGED_CHARACT_PRESENT;
  309.     err_code = softdevice_enable(&ble_enable_params);
  310.     APP_ERROR_CHECK(err_code);
  311.    
  312.     err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch);
  313.     APP_ERROR_CHECK(err_code);
  314. }
  315.  
  316. int main(void)
  317. {
  318.     uart_init();
  319.     ble_stack_init(true);
  320.    
  321.     while(1)
  322.     {
  323.         __WFI();
  324.     }
  325. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement