Keil Logo

OpenBLT and Keil RTX

Next Thread | Thread List | Previous Thread Start a Thread | Settings

Details Message
Author
Alain Messerli
Posted
20-Nov-2018 11:02 GMT
Toolset
ARM
New! OpenBLT and Keil RTX

Hello All,

my goal is to use the OpenBLT Bootloader on a STM32F103C6 to flash and later update a Keil RTX project.

The bootloader part (OpenBLT with UART Interface) is using the space between 0x08000000 to 0x08001800 on ROM and 0x20000000 to 0x20000C00 on RAM.

The RTX Application is unsing a scatter-file to create the file for flashing with the OpenBLT:

; *************************************************************
; *** Scatter-Loading Description File for OpenBLT          ***
; *************************************************************

LR_IROM1 0x08001800 0x00005800  {    ; load region size_region
  ER_IROM1 0x08001800 0x00005800  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000C00 0x00001C00  {  ; RW data
   .ANY (+RW +ZI)
  }
}

As described in the OpenBLT guide, the "Checksum placeholder" is placed at the end of the vector table of the RTX Project (startup_stm32f10x_ld.s):

                ...
                DCD     0                          ; Reserved
                DCD     EXTI15_10_IRQHandler       ; EXTI Line 15..10
                DCD     RTCAlarm_IRQHandler        ; RTC Alarm through EXTI Line
                DCD     USBWakeUp_IRQHandler       ; USB Wakeup from suspend
                DCD     0x55AA11EE                 ; OpenBLT Checksum Reserved place
__Vectors_End

The BOOT_FLASH_VECTOR_TABLE_CS_OFFSET is set to 0x130 in the flash.c file.

When I try to flash an RTX-like Project, the application is calling immediately the _sys_exit() function. (I'm using the

#pragma import(__use_no_semihosting)

and have implemented the function to get over the BKPT 0xAB).

When I try to flash an non-RTX Project, the application is running fine.

I think, that the problem is somewhere in the initializing code of the RTX kernel, maybe some Stack or Heap related part, but I really don't know where to start, because debugging is only possible when running the OpenBLT application and then following the program in the disassembly window...

Unfortunately I havent found a OpenBLT example who includes an Keil RTX program to run, only non-RTX examples.

Thanks

Alain

Author
Robert Rostohar
Posted
20-Nov-2018 12:19 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

The _sys_exit() might be called due to not enough heap (depending on the C library used).

Heap is typically configured in the startup file. Try to increase the heap.

Author
Alain Messerli
Posted
20-Nov-2018 12:45 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Hi Robert,

thanks for your answer.

I've increased the heap in the Bootloader application and also in the RTX application from 0x200 to 0x400 but no success. Should I increase the heap on the Bootloader or RTX application or both?

I can now debug the "flashed" firmware by downloading it by debugger (wrong OpenBLT checksum) and re-flashing it with the OpenBLT flasher (= creates correct checksum). So I can see, where the problem occours.

Right at the jump to the __main symbol the application goes into hard fault. So maybe the location of the __main (library init) is wrong?

; Reset handler routine
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
     IMPORT  __main
     IMPORT  SystemInit
                                 LDR     R1, =__initial_sp                      ; Added for OpenBLT support
                                 MOV     SP, R1
                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main            ; -> loading jump address
                 BX      R0                     ; -> Hard fault when jumping
                 ENDP

The __main jump address is 0x080018F0, loaded in R0 is the value 0x080018F1 but I think, this is correct.

Author
Robert Rostohar
Posted
20-Nov-2018 13:25 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Assuming that _sys_exit() was called from the application then the heap of the application should matter.

Are you sure that the hard fault occurs right at the jump to _main or maybe inside _main? The _main address and R0 seem ok, therefore it is more likely that the hard fault occurred within _main. Try to debug and figure out why the hard fault occurs and who triggered it.

Take a look at the following application note which also explains how to "Debug faults with uVision" (page 15):
http://www.keil.com/appnotes/files/apnt209.pdf

Author
Alain Messerli
Posted
20-Nov-2018 14:15 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Hi Robert,

thanks for your answer. By stepping through the disassembly window, the fault is inside the __main function.

Somehow the function _platform_post_lib_init (in RTX_CM_lib.h) gets called who contains the following:

__asm void _platform_post_lib_init (void) {

  IMPORT  os_thread_def_main
  IMPORT  osKernelInitialize
  IMPORT  osKernelStart
  IMPORT  osThreadCreate
  IMPORT  exit

  ADD     SP,#0x10
  BL      osKernelInitialize
  LDR     R0,=os_thread_def_main
  MOVS    R1,#0
  BL      osThreadCreate
  BL      osKernelStart
  BL      exit

  ALIGN
}

Inside of this function, the hard fault occures on the osKernelStart function, or better said, at the end of it.

The caller code (as mentioned in the app note), leads to the function sysTimerTick(). But I think the problem here is the initial call to the _platform_post_lib_init, because this looks like an "empty" rtx start with no threads, so the exit function is called and therefore the hard fault.

So why is this function called?

Author
Robert McNamara
Posted
20-Nov-2018 14:24 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

You probably need to make sure you have remapped the vector table before you call the app main.

Author
Robert Rostohar
Posted
20-Nov-2018 14:39 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Function _platform_post_lib_init is a hook called from __main by the C library.

osKernelStart should never return when there are no errors and execution should switch to main function (via os_thread_def_main thread).

It seems that something goes wrong inside osKernelStart (or already in osKernelInitialize).

Is the bootloader changing some system properties and not restoring them to reset values?

And as pointed out by Mr. McNamara: is the vector table remapped?

Author
Alain Messerli
Posted
20-Nov-2018 14:51 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Hello Together,

alright, so the jump from the OpenBLT to the RTX application is made here (applies only to the OpenBLT application, not the RTX application):

/************************************************************************************//**
** \brief     Starts the user program, if one is present. In this case this function
**            does not return.
** \return    none.
**
****************************************************************************************/
void CpuStartUserProgram(void)
{
  void (*pProgResetHandler)(void);

#ifndef BLT_IGNORE_CHECKSUM
  /* check if a user program is present by verifying the checksum */
  if (NvmVerifyChecksum() == BLT_FALSE)
  {
    /* not a valid user program so it cannot be started */
    return;
  }
#endif
#if (BOOT_CPU_USER_PROGRAM_START_HOOK > 0)
  /* invoke callback */
  if (CpuUserProgramStartHook() == BLT_FALSE)
  {
    /* callback requests the user program to not be started */
    return;
  }
#endif
#if (BOOT_COM_ENABLE > 0)
  /* release the communication interface */
  ComFree();
#endif
  CpuIrqDisable();
  /* reset the timer */
  TimerReset();
  /* remap user program's vector table */
  SCB_VTOR = CPU_USER_PROGRAM_VECTABLE_OFFSET & (blt_int32u)0x1FFFFF80;
  /* set the address where the bootloader needs to jump to. this is the address of
   * the 2nd entry in the user program's vector table. this address points to the
   * user program's reset handler.
   */
  pProgResetHandler = (void(*)(void))(*((blt_addr *)CPU_USER_PROGRAM_STARTADDR_PTR));
  /* The Cortex-M3 core has interrupts enabled out of reset. the bootloader
   * explicitly disables these for security reasons. Enable them here again, so it does
   * not have to be done by the user program.
   */
  CpuIrqEnable();
  /* start the user program by activating its reset interrupt service routine */
  pProgResetHandler();
} /*** end of CpuStartUserProgram ***/

- The BLT_IGNORE_CHECKSUM is a own define who I made to skip the OpenBLT checksum verification, this is currently not defined.
- The BOOT_CPU_USER_PROGRAM_START_HOOK is also zero, because I don't need this
- The BOOT_COM_ENABLE is set to 1, because I need the UART for the bootloader

Following the called functions:

/************************************************************************************//**
** \brief     Releases the communication module.
** \return    none
**
****************************************************************************************/
void ComFree(void)
{
#if (BOOT_COM_USB_ENABLE > 0)
  /* disconnect the usb device from the usb host */
  UsbFree();
#endif
} /*** end of ComFree ***/
/************************************************************************************//**
** \brief     Disable global interrupts.
** \return    none.
**
****************************************************************************************/
void CpuIrqDisable(void)
{
  __asm volatile ("cpsid i");
} /*** end of CpuIrqDisable ***/
/************************************************************************************//**
** \brief     Reset the timer by placing the timer back into it's default reset
**            configuration.
** \return    none.
**
****************************************************************************************/
void TimerReset(void)
{
  /* set the systick's status and control register back into the default reset value */
  SYSTICK->CTRL = 0;
} /* end of TimerReset */
/************************************************************************************//**
** \brief     Enable global interrupts.
** \return    none.
**
****************************************************************************************/
void CpuIrqEnable(void)
{
  __asm volatile ("cpsie i");
} /*** end of CpuIrqEnable ***/

Then the define CPU_USER_PROGRAM_VECTABLE_OFFSET is set to 0x08001800 and CPU_USER_PROGRAM_STARTADDR_PTR is set to 0x08001804.

On the other hand, at the SystemInit function of the RTX application, the Vector Offset register is not touched:

/**
  * @brief  Setup the microcontroller system
  *         Initialize the Embedded Flash Interface, the PLL and update the
  *         SystemCoreClock variable.
  * @note   This function should be used only after reset.
  * @param  None
  * @retval None
  */
void SystemInit (void)
{
  /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  /* Set HSION bit */
  RCC->CR |= (uint32_t)0x00000001;

  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL
  RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
  RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */

  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
  RCC->CFGR &= (uint32_t)0xFF80FFFF;

#ifdef STM32F10X_CL
  /* Reset PLL2ON and PLL3ON bits */
  RCC->CR &= (uint32_t)0xEBFFFFFF;

  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x00FF0000;

  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000;

  /* Reset CFGR2 register */
  RCC->CFGR2 = 0x00000000;
#else
  /* Disable all interrupts and clear pending bits  */
  RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */

#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
  #ifdef DATA_IN_ExtSRAM
    SystemInit_ExtMemCtl();
  #endif /* DATA_IN_ExtSRAM */
#endif

  /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
  /* Configure the Flash Latency cycles and enable prefetch buffer */
  SetSysClock();

//#ifdef VECT_TAB_SRAM
//  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
//#else
//  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
//#endif
}
Author
Robert Rostohar
Posted
20-Nov-2018 15:04 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

The application is started via pProgResetHandler read out form the application vector table (CPU_USER_PROGRAM_VECTABLE_OFFSET + 4).

However the stack pointer is not configured based on the application (first entry of the application vector table) but rather inherited from the bootloader. Maybe this is causing issues.

Also is the core left in handler mode and using MSP (as default out of reset)? Otherwise RTX initialization and startup might fail.

Author
Alain Messerli
Posted
20-Nov-2018 15:26 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Hi Robert,

thanks for your feedback.

The stack pointer should be set to the applications stack pointer on the SystemInit at the RTX application:

; Reset handler routine
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
     IMPORT  __main
     IMPORT  SystemInit
                 LDR     R1, =__initial_sp      ; Load position of SP
                 MOV     SP, R1                 ; set SP to position
                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

While stepping through, the SP is located at the following addresses:
0x20000D68 on reset
0x20000D50 when entering this Reset_Handler and
0x200024D8 after moving R1 into SP

About the core modes: I'm not so sure about that, but as far that I know, the core is started in thread mode with privileged access.

Author
Robert Rostohar
Posted
20-Nov-2018 15:54 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Have you tried the RTX application without the bootloader?

If yes, you could check with the debugger what behaves differently.

Author
Alain Messerli
Posted
22-Nov-2018 06:49 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Hi Robert,

so I've debugged the last days to check various things.

What I've found out (and will be most obvious to you I think) is, that the _platform_post_lib_init() function is used to create a main thread to call the user code main() function.

After creating the thread, the osKernelStart is called and should execute the main thread and thus should never "return" to the _platform_post_lib_init() function where the next instruction is the exit = hard fault, if semihosting is enabled...

Anyhow, the problem seems to be in the creation of the task. So the function svcThreadCreate() could not create the main task and so no task is running when the kernel starts.

// Thread Service Calls

/// Create a thread and add it to Active Threads and set it to state READY
osThreadId svcThreadCreate (const osThreadDef_t *thread_def, void *argument) {
  P_TCB  ptcb;
  OS_TID tsk;
  void  *stk;

  if ((thread_def == NULL) ||
      (thread_def->pthread == NULL) ||
      (thread_def->tpriority < osPriorityIdle) ||
      (thread_def->tpriority > osPriorityRealtime)) {
    sysThreadError(osErrorParameter);
    return NULL;
  }

  if (thread_def->stacksize != 0U) {            // Custom stack size
    stk = rt_alloc_mem(                         // Allocate stack
      os_stack_mem,
      thread_def->stacksize
    );
    if (stk == NULL) {
      sysThreadError(osErrorNoMemory);          // Out of memory
      return NULL;
    }
  } else {                                      // Default stack size
    stk = NULL;
  }

  tsk = rt_tsk_create(                          // Create task
    (FUNCP)thread_def->pthread,                 // Task function pointer
    (uint32_t)
    (thread_def->tpriority-osPriorityIdle+1) |  // Task priority
    (thread_def->stacksize << 8),               // Task stack size in bytes
    stk,                                        // Pointer to task's stack
    argument                                    // Argument to the task
  );

  if (tsk == 0U) {                              // Invalid task ID
    if (stk != NULL) {
      rt_free_mem(os_stack_mem, stk);           // Free allocated stack
    }
    sysThreadError(osErrorNoMemory);            // Create task failed (Out of memory)
    return NULL;
  }

  ptcb = (P_TCB)os_active_TCB[tsk - 1U];        // TCB pointer

  *((uint32_t *)ptcb->tsk_stack + 13) = (uint32_t)osThreadExit;

  return ptcb;
}
Author
Robert Rostohar
Posted
22-Nov-2018 06:58 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Where exactly does the svcThreadCreate() function fail?

Author
Alain Messerli
Posted
22-Nov-2018 08:07 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Hi Robert,

I think it's a problem inside the rt_tsk_create() function where a memory box should be allocated:

OS_TID rt_tsk_create (FUNCP task, U32 prio_stksz, void *stk, void *argv) {
  /* Start a new task declared with "task". */
  P_TCB task_context;
  U32 i;

  /* Priority 0 is reserved for idle task! */
  if ((prio_stksz & 0xFFU) == 0U) {
    prio_stksz += 1U;
  }
  task_context = rt_alloc_box (mp_tcb);
  if (task_context == NULL) {
    return (0U);
  }
  /* If "size != 0" use a private user provided stack. */
  task_context->stack      = stk;
  task_context->priv_stack = (U16)(prio_stksz >> 8);
  /* Pass parameter 'argv' to 'rt_init_context' */
  task_context->msg = argv;
  /* For 'size == 0' system allocates the user stack from the memory pool. */
  rt_init_context (task_context, (U8)(prio_stksz & 0xFFU), task);

  /* Find a free entry in 'os_active_TCB' table. */
  i = rt_get_TID ();
  if (i == 0U) {
    return (0U);
  }
  os_active_TCB[i-1U] = task_context;
  task_context->task_id = (U8)i;
  DBG_TASK_NOTIFY(task_context, __TRUE);
  rt_dispatch (task_context);
  return ((OS_TID)i);
}

on the line where rt_alloc_box() gets called, the task_conext is Null because the function call returns after this line. It's a bit tricky because this code is only as assembler available and some of it can't get accessed with the debugger. For example I can't get the content of the tast_context but jumping to the return statement let's me guess, that there is a problem with this.

Here is the called function where the __USE_EXCLUSIVE_ACCESS is defined (so the #else part is running):

void *rt_alloc_box (void *box_mem) {
  /* Allocate a memory block and return start address. */
  void **free;
#ifndef __USE_EXCLUSIVE_ACCESS
  U32  irq_mask;

  irq_mask = (U32)__disable_irq ();
  free = ((P_BM) box_mem)->free;
  if (free) {
    ((P_BM) box_mem)->free = *free;
  }
  if (irq_mask == 0U) { __enable_irq (); }
#else
  do {
    if ((free = (void **)__ldrex(&((P_BM) box_mem)->free)) == 0U) {
      __clrex();
      break;
    }
  } while (__strex((U32)*free, &((P_BM) box_mem)->free));
#endif
  return (free);
}




Author
Robert Rostohar
Posted
22-Nov-2018 10:26 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

It looks as if the memory for task control block could not be allocated. This should normally not occur since the memory is provided statically by the kernel.

Are you sure that rt_tsk_create() fails due to rt_alloc_box() returning NULL?

Even if the main thread could not be created, the function osKernelStart() should not return but switch to the Idle task which is created implicitly during osKernelInitialize().

I suggest you debug further and check first osKernelInitialize() and then osKernelStart().

Or you could try out a simple RTX based example without using the bootloader and examine what is different. Maybe you have a tool or configuration issue.

You could take a look at existing examples (Blinky) found in the Device Family Pack for STM32F1 (http://www.keil.com/dd2/pack/).

It should be also very easy to create a test project with empty main that uses RTX and verify that is starts properly. It takes less than a minute (a few clicks) to create an RTX project with MDK and using Run-Time Environment.
It can be also configured for the simulator.

You could also consider the newer RTX5 (CMSIS RTOS2) with many new features (available as source code also - so debugging should be eaiser).

Author
Robert McNamara
Posted
22-Nov-2018 18:20 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Try these in conjunction with what Robert #1 suggested.

1) See that your RTX_Config.c file is configured properly. Make sure you are looking at the EXACT one that is being used.

2) Look in the map file and see how much space is allocated for mp_tcb, mp_stk, os_stack_mem and make sure it matches what your RTX_Config.c files thinks they should be.

3) For a test, build a scatter file for the APP that loads at 0x08000000, rebuild and overwrite the bootloader and see if this runs properly or not.

An item of interest is that the Bootloader seems to set the stack to the highest RAM address as opposed to something within the range of 0x20000000 and 0x20000C00. Probably not your issue, but if you are really intending to keep these 2 separate, they are not.

It looks as if the memory for task control block could not be allocated. This should normally not occur since the memory is provided statically by the kernel.

Yes it is not something that occurs on its own, but it is only "semi" statically allocated. It can be set to 0 (i.e. it is possible that this is "empty" or "has no items" in it, but the compiler will not tell you that (so not quite statically allocated). As it seems that the rt_alloc_box for the STACKS may also be failing, maybe it is also zero or something else is wrong but related what makes the rt_alloc fail for both the TCB and Stack area's.

Even if the main thread could not be created, the function osKernelStart() should not return but switch to the Idle task which is created implicitly during osKernelInitialize().

Yes and I am not seeing any reason to believe that it not being scheduled and dispatched. It would seem that it is probably the only thread the system thinks it has. The TCB for the idle thread is statically allocated (it is REALLY statically allocated such that if it compiles space for it will exist). My guess is the rt_alloc for the stack for the Idle thread is failing, and this causes it to be set to 0. When the initial stack frame is generated and the stack adjusted, it will not actually be pointing to or set to anything valid. I believe the hard fault comes when the system "returns" to the idle thread.

I suggest you debug further and check first osKernelInitialize() and then osKernelStart().

And remember (or note) you can add the source code to the os to your application and it will allow you to do source level debugging of your app including the os. (just make sure that after you add the files, you select do not include in build)

You could take a look at existing examples (Blinky) found in the Device Family Pack for STM32F1 (http://www.keil.com/dd2/pack/).

Yes, the blinky examples are always great.

Author
Alain Messerli
Posted
23-Nov-2018 06:55 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Hi Robert,

thanks for your answer. Unfortunately changing/upgrading the rtos seems to much for me, due to licensing and affected products. But I've created a simple blinky project (who matches my hardware) and the problem occures too. So I've debugged a lot and found out, that the variables os_initialized and os_running are not set to zero when I start the application and thus the memory box (who is used to allocate memory for everything in the rtx) is not created. If I add the following code into the startup reset handler:

; Reset handler routine
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
         IMPORT  __main
         IMPORT  SystemInit
         IMPORT  ClearSpecial
                 LDR     R1, =__initial_sp                      ; Added for OpenBLT support
                 MOV     SP, R1

                 LDR     R0, =ClearSpecial
                 BLX     R0

                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

and then in my c-code:

void ClearSpecial(void)
{
        os_initialized = 0;
        os_running = 0;
}

the RTX code works (!), but only on the "simple" blinky project.

When I went further to use this on my application, who I want to use with the OpenBLT, the kernel starts and the threads were initialized, but after the threads are running I get again a hardfault.

This time the hardfault is fired "somewhere". By somewhere I mean that while stepping through the code, that I think not the shown code in the debugger is causing the issue, but more some IRQ related part...

As I've looked into the *.map file I found, that the both variables are data (for me = not zero initialized). So they must be initialized somewhere in the startup / arm library, because the RTX is running when I don't use the bootloader part.

So I've set an access-breakpoint on the os_initialized (write) and "found" the function __scatterload. So now I'm observing this (but I wanted to inform you about it), because I think my problems are caused by some not-initialized variables...

Author
Alain Messerli
Posted
23-Nov-2018 13:33 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Hello together,

sorry for you Robert #2, I haven't seen your reply but finally I got things running. But I'm a bit confused, if I've found the "best practise" solution for it. So to summarize what I've done (and as a possible ToDo-List for future projects):

- Prepare the OpenBLT depending on your needs (in my case only UART is needed)

- Specify on your own, which memory addresses are used for the bootloader and the rtx application you would like to run, depending on used microcontroller in my case a STM32F103C6: + OpenBLT (only with UART), ROM from 0x08000000 - 0x080017FF, RAM from 0x2000000 - 0x20000BFF + RTX App, ROM from 0x080001800 - 0x08008000, RAM from 0x20000C00 - 0x20002800

- Apply the OpenBLT specific settings (vector table offset, checksum placeholder) on the bootloader application

- To run the RTX application with the OpenBLT, the semihosting must be disabled with the following pragma in the c-code, in my case placed in the main.c file:

#pragma import(__use_no_semihosting)

- After compiling, implement the needed semihosting functions (like in retarget.c, the compiler should tell you the missing functions) like the _sys_exit:

void _sys_exit(int code)
{
        // in my case: just reset to re-run the application, replace with more specific solution
        NVIC_SystemReset();
}

- Implement an "RTX Reset" function, who cleares the os_initialized and os_running variables, call it at the startup of the RTX application, in my case the function is named "ClearSpecial" in startup_stm32f10x_ld.s:

; Reset handler routine
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
     IMPORT  __main
     IMPORT  SystemInit
     IMPORT  ClearSpecial
                 LDR     R1, =__initial_sp                      ; Added for OpenBLT support to get the correct stack pointer location
                 MOV     SP, R1
                 LDR     R0, =ClearSpecial                      ; Added for RTX support
                 BLX     R0
                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

void ClearSpecial(void)
{
        os_initialized = 0;
        os_running = 0;
}

- Use a scatter file for relocating the RTX application:

; *************************************************************
; *** Scatter-Loading Description File for OpenBLT          ***
; *************************************************************

LR_IROM1 0x08001800 0x00005800  {    ; load region size_region
  ER_IROM1 0x08001800 0x00005800  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000C00 0x00001C00  {  ; RW data
   .ANY (+RW +ZI)
  }
}

- Edit the core_cm3.h file definitions (line 250 and 256 in original) to place constant variables in ROM and not in RAM. To do this, explore to the file and remove the write-protection and edit the following:

/* IO definitions (access restrictions to peripheral registers) */
/**
    \defgroup CMSIS_glob_defs CMSIS Global Defines

    <strong>IO Type Qualifiers</strong> are used
    \li to specify the access to peripheral variables.
    \li for automatic generation of peripheral register debug information.
*/
#ifdef __cplusplus
  #define   __I     volatile             /*!< Defines 'read only' permissions */
#else
  //#define   __I     volatile const       /*!< Defines 'read only' permissions */
  #define   __I     const       /*!< Defines 'read only' permissions, special version for compiler V5.05, update 2, build 169 */
#endif
#define     __O     volatile             /*!< Defines 'write only' permissions */
#define     __IO    volatile             /*!< Defines 'read / write' permissions */

/* following defines should be used for structure members */
//#define     __IM     volatile const      /*! Defines 'read only' structure member permissions */
#define     __IM     const      /*! Defines 'read only' structure member permissions, special version for compiler V5.05, update 2, build 169 */
#define     __OM     volatile            /*! Defines 'write only' structure member permissions */
#define     __IOM    volatile            /*! Defines 'read / write' structure member permissions */

/*@} end of group Cortex_M3 */

- Add the after build command in the RTX application to generate a *.srec file, used by the OpenBLT MicroBoot application (Options for Target->User->Run #1), and don't forget to check the checkbox!

fromelf --m32 --output=OutputDirectory\RTX_App.srec OutputDirectory\RTX_App.axf --cpu Cortex-M3

To debug the RTX application, do the following: + Compile the OpenBLT application and flash the microcontroller + Compile the RTX application and flash the microcontroller (start a debug-session) + Flash the controller again with the MicroBoot application (microcontroller isn't leaving the bootloader, because the checksum is incorrect until the RTX application is flashed within the bootloader)

- Be happy!

Author
Alain Messerli
Posted
23-Nov-2018 13:35 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

There is a character limit of 7000 per post ;-)

My final thoughts on this one is the editing of the CMSIS library. I think this isn't a good way to do this, but I'm unaware, where I could change this. When I got the 2nd hardfault I was wondering about the clock speeds of the microcontroller, read by the function RCC_GetClocksFreq(): PCLK1 and PCLK2 were set to 72MHz (SYSCLK), what was a bit surprising. Then when running the RTX application without the bootloader, the clock speeds were PCLK1 32MHz, PCLK2 72MHz. 32MHz on the PCLK1 is the maximum and should not exceed! So I've found out, that the function is using a table to determine the frequencies:

(snippet from RCC_GetClocksFreq())
/* Get PCLK1 prescaler */
  tmp = RCC->CFGR & CFGR_PPRE1_Set_Mask;
  tmp = tmp >> 8;
  presc = APBAHBPrescTable[tmp];
  /* PCLK1 clock frequency */
  RCC_Clocks->PCLK1_Frequency = RCC_Clocks->HCLK_Frequency >> presc;
  /* Get PCLK2 prescaler */
  tmp = RCC->CFGR & CFGR_PPRE2_Set_Mask;
  tmp = tmp >> 11;
  presc = APBAHBPrescTable[tmp];
  /* PCLK2 clock frequency */
  RCC_Clocks->PCLK2_Frequency = RCC_Clocks->HCLK_Frequency >> presc;


where the table is located in stm32f10x_rcc.c:

/** @defgroup RCC_Private_Variables
  * @{
  */

static __I uint8_t APBAHBPrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9};
static __I uint8_t ADCPrescTable[4] = {2, 4, 6, 8};


and the macro __I is defined as (in core_cm3.h):

#define   __I     volatile const       /*!< Defines 'read only' permissions */

So normally I've expected to locate the const array in the RO section but the map-file tells me, that this table is located in RAM?!?:

    APBAHBPrescTable                         0x20000cd8   Data          16  stm32f10x_rcc.o(.data)
    ADCPrescTable                            0x20000ce8   Data           4  stm32f10x_rcc.o(.data)

With the debugger I could see, that the RAM is cleared "somewhere" and thus not filled up with the const data! (I think the initializing function is erazing the wrong sectors...). And by changing the __I macro to

#define   __I     const       /*!< Defines 'read only' permissions, special version for compiler V5.05, update 2, build 169 */


the map-file looks like expected (in ROM):

    APBAHBPrescTable                         0x08006e98   Data          16  stm32f10x_rcc.o(.constdata)

So I guess this could be very specific, so here are my versions:

Toolchain:          MDK-ARM Standard Cortex-M only: 1 user(s)  Version: 5.15.0
Toolchain Path:     C:\Keil_v5\ARM\ARMCC\Bin
C Compiler:         Armcc.exe                                  V5.05 update 2 (build 169)
Assembler:          Armasm.exe                                 V5.05 update 2 (build 169)
Linker/Locator:     ArmLink.exe                                V5.05 update 2 (build 169)
Library Manager:    ArmAr.exe                                  V5.05 update 2 (build 169)
Hex Converter:      FromElf.exe                                V5.05 update 2 (build 169)
CPU DLL:            SARMCM3.DLL                                V5.15.0
Dialog DLL:         DCM.DLL                                    V1.13.2.0
Target DLL:         UL2CM3.DLL                                 V1.155.8.0
Dialog DLL:         TCM.DLL                                    V1.14.5.0
ARM::CMSIS          5.0.0-Beta4
STM32F1xx_DFP       1.1.0

So I would like to get your thoughts about this, I think I found a way around the problem but not the source of it...

Author
Robert Rostohar
Posted
23-Nov-2018 14:35 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

It seems that RW data (including zero initialized variables) is not properly initialized in your application. This is most likely causing the issues that you have seen and tried to bypass with different fixes.

"ClearSpecial" should not be needed since both os_xxx variables should be initialized to zero by the scatter loader.

Modifying the CMSIS core_cm3.h header file should also not be needed to overcome the RCCGetClocksFreq function implementation provided by ST.

It is true that the table APBAHBPrescTable and ADCPrescTable could be made const and would be located in ROM (not use any RAM). However even if they are located in RAM they should be initialized with the specified values by the scatter loader.

You should check what happens with the mentioned RW data initialization during bootloader and when the actual application is being started.

Author
Robert McNamara
Posted
23-Nov-2018 17:02 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Yes to all Robert #1 said.

Your MDK version is a little old, but probably not your issue. BUT, I would not count it out. Upgrading to something more recent (I still use 5.16a on a few active projects and I don't have issues running an RTX application from a bootloader)

So I would like to get your thoughts about this, I think I found a way around the problem but not the source of it...

IF your scatter loading for your RTX application is not executing properly I cannot imagine that you will not find something else that is not initialized and causes an issue. I don't think having variables not initialized and zero-init data not being zeroed is going to be OK for anything.

Bottom line is you are correct, there is a problem. Scatterloading not happening is a serious issue. Calling main() instead of __main() will cause Scatterloading to not happen, but also _platform_post_lib_init() would not get called, and it is.

I would step into __main() in the dissassembly window and then step into the __scatterload() function. It is the first function call after entering __main(). you need to determine if / way RW variables are not being initialized and 0 init variables are not zeroed.

If scatterloading is not happening properly you will likely have many problems as your application grows.

Maybe another test would be see if you can create a minimal bootloader that does nothing more then jump to the RTX application.

Author
Alain Messerli
Posted
26-Nov-2018 13:36 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Hello again,

thanks for your answers. Truly there must be something wrong with this scatterload function, but I've never seen/used it (and also questionned this basic functionality because it has always worked)...

Just to get this correctly and understand the functionality: the function call to the __scatterload is made to initialize variables with pre-defined values including zeroing some variables. As far as I understand, there is a __scatterload_copy and a __scatterload_zeroinit function to do exactly this.

The copy function is loading the variables with the pre-defined values and the zeroinit is filling other variables with zeroes.

Unfortunately I haven't found the "source code" of the __scatterload functions but with the *.map file I could set breakpoints where those functions are called. Or do you have a Idea of how to get to the source of this?

So I've changed back the __I definition and removed the call to the "ClearSpecial" function to get to the "basic", failing rtx application.

So here is the assembler code from the disassembly view:

                 __scatterload_copy:
0x0800192C 3A10      SUBS     r2,r2,#0x10
0x0800192E BF24      ITT      CS
0x08001930 371A      ADDCS    r7,r7,#0x1A
0x08001932 AFFF      ADDCS    r7,sp,#0x3FC
0x08001934 D8FA      BHI      __scatterload_copy (0x0800192C)
0x08001936 0752      LSLS     r2,r2,#29
0x08001938 BF24      ITT      CS
0x0800193A C830      LDMCS    r0!,{r4-r5}
0x0800193C C130      STMCS    r1!,{r4-r5}
0x0800193E BF44      ITT      MI
0x08001940 6804      LDRMI    r4,[r0,#0x00]
0x08001942 600C      STRMI    r4,[r1,#0x00]
0x08001944 4770      BX       lr
0x08001946 0000      MOVS     r0,r0
                 __scatterload_zeroinit:
0x08001948 2300      MOVS     r3,#0x00
0x0800194A 2400      MOVS     r4,#0x00
0x0800194C 2500      MOVS     r5,#0x00
0x0800194E 2600      MOVS     r6,#0x00
0x08001950 3A10      SUBS     r2,r2,#0x10
0x08001952 BF28      IT       CS
0x08001954 C178      STMCS    r1!,{r3-r6}
0x08001956 D8FB      BHI      0x08001950
0x08001958 0752      LSLS     r2,r2,#29
0x0800195A BF28      IT       CS
0x0800195C C130      STMCS    r1!,{r4-r5}
0x0800195E BF48      IT       MI
0x08001960 600B      STRMI    r3,[r1,#0x00]
0x08001962 4770      BX       lr

I've added a breakpoint on the line 0x0800192C and 0x08001948. So when entering the __scatterload_copy I have:

R0 =      0x08006E9C
R1 =      0x20000C00
R2 =      0x00000114
R3 =      0x0800192D
R4 =      0x08001AE1
R5 =      0x20000504
R6 =      0x00000000
R7 =      0x08006E7B
R8 =      0x00000000
R9 =      0x20000160
R10 =     0x08006E8C
R11 =     0x08006E9C
R12 =     0x00000008
R13(SP) = 0x20002750
R14(LR) = 0x08001907
R15(PC) = 0c0800192C

and when entering the __scatterload_zeroinit:

R0 =      0x08006FB0
R1 =      0x20000D14
R2 =      0x00001A3C
R3 =      0x08001949
R4 =      0x00000100
R5 =      0x20000504
R6 =      0x00000000
R7 =      0x20002B4C
R8 =      0x00000000
R9 =      0x20000160
R10 =     0x08006E9C
R11 =     0x08006E9C
R12 =     0x00000008
R13(SP) = 0x20002750
R14(LR) = 0x08001907
R15(PC) = 0c08001948

I'm a bit overwhelmed with the assembler code, but I saw there two addresses: 0x20000C00 in the copy function (R1) and 0x20000D14 in the zeroinit. Considering the *.map file I found that from 0x20000C00 to 0x20000D14 are .data variables located and from 0x20000D14 upwards .bss variables. For the note: the APBAHBPrescTable is located at 0x20000CD8 and the os_initialized and os_running at 0x20000CEC / 0x20000CED = in the .data section.

However, I think that the __scatterload_copy is using the wrong address to copy the initialization values and thus creating those problems, so I'm starting now to research those assembler commands to get the logic of the copy function and to get the address of the initialization values who should be stored in the ROM section I think...

Author
Robert McNamara
Posted
26-Nov-2018 15:55 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

What you have shown looks very correct. A basic project would have 1 copy section and 1 zero init section. The compiler will compress the copy data stored in flash if the total size of the compressed data and the code to decompress it is less then the total size of the uncompressed init data. (my guess is your data is compressed)

what values does os_initialized and os_running have immediately after calling the __scatterload_copy? If these are zero, are either of them non-zero at the osKernelInitialize call?

You should be able to tell if __scatterload_copy was sucessful as after it is run, ANY variable that is initialized you should be able to find it's address in the map file and then do a view memory in the debugger. If you think scatterloading is happening to/from a wrong address, provide more information on that.

There is not yet any indication that __scatterload_copy or __scatter_load_zeroinit is bad so no need to get the source for it. (the zero_init is extreamly simple to analyze for correctness in assembly language as well as copy for sections that are not compressed.)

It might be helpful if you can extract a few 32-bit values fro the Application code.

You should have a variable in the map file called Region$$Table$$Base.
The next 8 32-bit values may be helpful, though it really appears as if scatterload is setup properly. This should tell us if a wrong address is being used to copy from scatter loading wise.

Author
Alain Messerli
Posted
27-Nov-2018 07:54 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Hi Robert,

thanks for your message. So I've stepped through the __scatterload_copy and the os_initialized and os_running are 1 when I get to the __scatterload_copy, after it, they were also 1 and even after the __scatterload_zeroinit they were 1. For fun, I've set them to a value of 120 at the beginning of the __main call and they were untouched until the osKernelInitialize call, where they were set to 1, but because of the "non zero" value the memory don't gets allocated and so on...
On the other hand, when I set a variable who is in the zeroinit section to non-zero values at the beginning of the __main, the variable get's correctly set to zero, so I think we're on the right track here.

The variable Region$$Table$$Base is in my case located at 0x08006E7C and the Region$$Table$$Limit is located at 0x08006E9C.

The memory values are (hex from the memory window):

Address    = Hexhexhexhex = converted -> my guess, what this number means
0x08006E7C = 9C 6E 00 08 = 0x08006E9C -> end of this array
0x08006E80 = 00 0C 00 20 = 0x20000C00 -> scatterload starting address for initializing
0x08006E84 = 14 01 00 00 = 0x00000114 -> size for initializing
0x08006E88 = 2C 19 00 08 = 0x0800192C -> address of the copy function __scatterload_copy
0x08006E8C = B0 6F 00 08 = 0x08006FB0 -> special memory address?!?
0x08006E90 = 14 0D 00 20 = 0x20000D14 -> scatterload starting address for zeroing
0x08006E94 = 3C 1A 00 00 = 0x00001A3C -> size for zeroing
0x08006E98 = 48 19 00 08 = 0x08001948 -> address of the zero function __scatterload_zeroinit
0x08006E9C = 00 01 00 00 = 0x00000100 -> special size?!?

Can someone see some hint in the numbers? The "special memory address" seems suspicious to me but maybe that is just the "decompress" function...

Author
Robert McNamara
Posted
27-Nov-2018 17:22 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

No hint in the numbers. These are 4 parameters passed into the function call (that is also one of the parameters). 1st is the starting point in flash used in the copy. This value is not used for zeroinit so is usually just the last value it was (0x08006E9C + 0x0114) so I don't beleive there is anything "special" about "special memory address?!?". The "special size?!?" is past the end of the table so not related to scatterloading.

As I think Robert #1 pointed out, it seemed very likely that the initialization of some variables was not correct - most likely the os_initialized. It must be 0 for the os to initialize the memory boxes for the TCB and stacks. If they are not the stack allocation for the idle task fails (but this one does have a valid TCB because it is static) as well as every TCB allocation for threadcreate.

It concerns me that other parameters might not be initialized properly that are not so obvious, but maybe just as damaging at the point they are needed. This is why clearing these values individually just does not seem to be a good idea. The scatter loading should have you set up properly and if it is not, you need to understand why.

What address is os_initialized at?

Is this address within the range of one of the scatter load sections? Which one. I might be interesting to know if it is in the rw section or the zero_init. The scatter load table looks just fine. It seems to be calling the proper functions with valid parameters.

maybe you can put an write access break point at the address of os_initialized. Does it every get zeroed. Who is setting it to 1?

Author
Alain Messerli
Posted
28-Nov-2018 07:30 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Hi Robert,

thanks for your message. The os_initialized is at the address 0x20000CEC and so within the __scatterload_copy section (0x20000C00 - 0x20000D14) what is shown in the map file as ".data".

I've added the access breakpoint to the os_initialized and the only point, where this breakpoint is triggered, is at the end of the function svcKernelInitialize():

osStatus svcKernelInitialize (void) {
  uint32_t ret;

  if (os_initialized == 0U) {

    // Init Thread Stack Memory (must be 8-byte aligned)
    if (((uint32_t)os_stack_mem & 7U) != 0U) { return osErrorNoMemory; }
    ret = rt_init_mem(os_stack_mem, os_stack_sz);
    if (ret != 0U) { return osErrorNoMemory; }

    rt_sys_init();                              // RTX System Initialization
  }

  os_tsk.run->prio = 255U;                      // Highest priority

  if (os_initialized == 0U) {
    // Create OS Timers resources (Message Queue & Thread)
    osMessageQId_osTimerMessageQ = svcMessageCreate (&os_messageQ_def_osTimerMessageQ, NULL);
    osThreadId_osTimerThread = svcThreadCreate(&os_thread_def_osTimerThread, NULL);
  }

  sysThreadError(osOK);

  os_initialized = 1U; // <- here
  os_running = 0U;

  return osOK;
}
Author
Robert McNamara
Posted
28-Nov-2018 18:40 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

That is all correct EXCEPT there should be an access break during the scatter_copy when os_initialize gets initialized to the value 0.

I think you are going to need to remove the bootloader. Build your application to run from 0x08000000 and 0x20000000. Load and run it. Does it work properly. If it does not, you likely need to upgrade your MDK version. It looks like your current code size is small enough that a trial license would be fine at least to test that it works.

If it does work, then you will have to find out why when you combine this with the bootloader it fails.

Author
Alain Messerli
Posted
29-Nov-2018 15:44 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Hi Robert,

thanks for your message. So I've downloaded the newest MDK, the 5.26.2.0 and the result was always the same: no initialization of the non-zero variables, when using the bootloader. I've even tried different compiler versions, and updated the CMSIS Core but no success.

But what I've found while compiling and updating to the "new" MDK version were some differences in the __scatterload_copy function:

without bootloader part (initialization working):

                 __scatterload_copy:
0x0800012C 3A10      SUBS     r2,r2,#0x10
0x0800012E BF24      ITT      CS
0x08000130 C878      LDMCS    r0!,{r3-r6}
0x08000132 C178      STMCS    r1!,{r3-r6}
0x08000134 D8FA      BHI      __scatterload_copy (0x0800012C)
0x08000136 0752      LSLS     r2,r2,#29
0x08000138 BF24      ITT      CS
0x0800013A C830      LDMCS    r0!,{r4-r5}
0x0800013C C130      STMCS    r1!,{r4-r5}
0x0800013E BF44      ITT      MI
0x08000140 6804      LDRMI    r4,[r0,#0x00]
0x08000142 600C      STRMI    r4,[r1,#0x00]
0x08000144 4770      BX       lr
0x08000146 0000      MOVS     r0,r0

with bootloader (no initialization):

                 __scatterload_copy:
0x0800192C 3A10      SUBS     r2,r2,#0x10
0x0800192E BF24      ITT      CS
0x08001930 3AE2      SUBCS    r2,r2,#0xE2
0x08001932 AFFF      ADDCS    r7,sp,#0x3FC
0x08001934 D8FA      BHI      __scatterload_copy (0x0800192C)
0x08001936 0752      LSLS     r2,r2,#29
0x08001938 BF24      ITT      CS
0x0800193A C830      LDMCS    r0!,{r4-r5}
0x0800193C C130      STMCS    r1!,{r4-r5}
0x0800193E BF44      ITT      MI
0x08001940 6804      LDRMI    r4,[r0,#0x00]
0x08001942 600C      STRMI    r4,[r1,#0x00]
0x08001944 4770      BX       lr
0x08001946 0000      MOVS     r0,r0

So there are differences depending only on the different start address. But I'm a bit lost here...

Author
Robert McNamara
Posted
29-Nov-2018 16:17 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

I am not seeing anything different in the scatterloading code based on Load address. IF it is calling that code it certainly will not initialize the rw data.

Can you build the "offset" file (your app) and generate a binary file from it. Can you see if the bytes at the same offset in the binary file and see if 0x1930 and 0x1932 have proper files. Is it possible that your bootloader is actually changing this offset file before it gets into the flash (either on the host or as it is copied/burned to the flash the flash)

                 __scatterload_copy:
0x0800192C 3A10      SUBS     r2,r2,#0x10
0x0800192E BF24      ITT      CS
0x08001930 3AE2      SUBCS    r2,r2,#0xE2      ; <<< here. is it C878 or 3AE2
0x08001932 AFFF      ADDCS    r7,sp,#0x3FC     ; <<< here. is it AFFF or C178
0x08001934 D8FA      BHI      __scatterload_copy (0x0800192C)

I have no experience with OpenBLT, So I am not sure what the chances are that it is changing the file/data, but that does look to be bad scatterloading code and it seems more likley to me that something has changed it rather then it being generated wrong.

Actually maybe a good test would be to remove the bootloader. Build the app for 0x08001800. Flash the app. Go into the debugger and see the dissasembly at 0x08001800 (actually 0x0800192C forward if it is the same build as above).

Author
Alain Messerli
Posted
30-Nov-2018 09:51 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Hi Robert,

thanks for your hint! Actually I think I found the problem to all this, It's the wrong vector table offset for the OpenBLT checksum (bummer!), but here are the steps of what I've done:

As you said, I've loaded the "offset" binary to the microcontroller and started the debugger. Obviously the programm was waiting in the OpenBLT bootloader because the needed checksum was not there. So I've stopped the target and went to the scatterload function:

                 __scatterload_copy:
0x0800192C 3A10      SUBS     r2,r2,#0x10
0x0800192E BF24      ITT      CS
0x08001930 C878      LDMCS    r0!,{r3-r6}
0x08001932 C178      STMCS    r1!,{r3-r6}
0x08001934 D8FA      BHI      __scatterload_copy (0x0800192C)
0x08001936 0752      LSLS     r2,r2,#29
0x08001938 BF24      ITT      CS
0x0800193A C830      LDMCS    r0!,{r4-r5}
0x0800193C C130      STMCS    r1!,{r4-r5}
0x0800193E BF44      ITT      MI
0x08001940 6804      LDRMI    r4,[r0,#0x00]
0x08001942 600C      STRMI    r4,[r1,#0x00]
0x08001944 4770      BX       lr
0x08001946 0000      MOVS     r0,r0

I thaught: perfect, so the reason of my problems were that the openblt is messing with my code so the whole thing is unusable...

Anyway I went back to the bootloader application (this wasn't touched because I didn't changed this) and stepped through the code. Somewhere there was this BOOT_FLASH_VECTOR_TABLE_CS_OFFSET who I set to 0x130. Reviewing once again the *.map file of the rtx application I found a symbol called __Vectors_Size with a value of 0xF0. Well if the vectorsize is 0xF0, why do I offset the checksum to 0x130? Because I've used the reference manual where the vector table for "other STM32F10xx devices" ended at 0x12C, so the next word address would be 0x130. But considering the startup file, the interrupts after USBWakeUp_IRQHandler were inexistent (at address 0x0E8) and so the CORRECT place for the checksum offset is 0xEC and not 0x130.

So guess what lies at the position of 0x08001800 + 0x130? Right, its the address 0x08001930 where the two instructions for the __scatterload_copy functions are located. This is so fun, I mean what the heck ;-)

Changed the checksum offset to the right value and everything works as expected! No change on libraries or special initializations.

So finally I have to thank you all to stay with me in this special case! I've learned very much about the basic functionality, scatter files and the fascination information of a map file ;-) and could finally solve it.

To round things up I would like to ask you a last question: why are there no "hints" or informations about the different vector tables on the STM32F103C6? Because I've just used the "regular" reference manual: https://www.st.com/resource/en/reference_manual/cd00171190.pdf

Or is this a "special" one because normally you don't go into the startup file and do stuff there.

Many thanks!

Alain

Author
Robert McNamara
Posted
30-Nov-2018 17:59 GMT
Toolset
ARM
New! RE: OpenBLT and Keil RTX

Good job! Suggesting that 2 instructions were being overwritten (and JUST those 2) seemed very odd, but the instructions provided no useful algorithm that I could identify as if they were almost random bytes and certainly were not what I have ALWAYS seen when I have looked at the __scatter_copy function (which is almost never because, why would anyone EVER need to look at the __scatter_copy code. It just "works" and you just use it - usually without even knowing you're using it.)


To round things up I would like to ask you a last question: why are there no "hints" or informations about the different vector tables on the STM32F103C6? Because I've just used the "regular" reference manual: https://www.st.com/resource/en/reference_manual/cd00171190.pdf

I understand your pain here. The "regular" reference manual you reference above is the specific reference manual for the STM32F103C6 as well as the entire STM32F1xx line of chips.

They really did leave "hints" and even some information. A lot of hints.

Section 1 show what is implemented in each different variation of the chips. The Low Density does not support as many devices and therefore does not need to support as many interrupt vectors. There would have been no harm to have unusable vectors in your table so you could have used offset 0x130, but you did need to let OpenBLT know what location you were using.

Also looking at the specific stm32f10x.h would have given you a nice hint. Below is the part for Low Density Chips. The big "hint" in this file is that the last entry is USBWakeUp_IRQn at "index 42"

typedef enum IRQn
{
/******  Cortex-M3 Processor Exceptions Numbers ***************************************************/
  NonMaskableInt_IRQn         = -14,    /*!< 2 Non Maskable Interrupt                             */
  MemoryManagement_IRQn       = -12,    /*!< 4 Cortex-M3 Memory Management Interrupt              */
  BusFault_IRQn               = -11,    /*!< 5 Cortex-M3 Bus Fault Interrupt                      */
  UsageFault_IRQn             = -10,    /*!< 6 Cortex-M3 Usage Fault Interrupt                    */
  SVCall_IRQn                 = -5,     /*!< 11 Cortex-M3 SV Call Interrupt                       */
  DebugMonitor_IRQn           = -4,     /*!< 12 Cortex-M3 Debug Monitor Interrupt                 */
  PendSV_IRQn                 = -2,     /*!< 14 Cortex-M3 Pend SV Interrupt                       */
  SysTick_IRQn                = -1,     /*!< 15 Cortex-M3 System Tick Interrupt                   */

/******  STM32 specific Interrupt Numbers *********************************************************/
  WWDG_IRQn                   = 0,      /*!< Window WatchDog Interrupt                            */
  PVD_IRQn                    = 1,      /*!< PVD through EXTI Line detection Interrupt            */
  TAMPER_IRQn                 = 2,      /*!< Tamper Interrupt                                     */
  RTC_IRQn                    = 3,      /*!< RTC global Interrupt                                 */
  FLASH_IRQn                  = 4,      /*!< FLASH global Interrupt                               */
  RCC_IRQn                    = 5,      /*!< RCC global Interrupt                                 */
  EXTI0_IRQn                  = 6,      /*!< EXTI Line0 Interrupt                                 */
  EXTI1_IRQn                  = 7,      /*!< EXTI Line1 Interrupt                                 */
  EXTI2_IRQn                  = 8,      /*!< EXTI Line2 Interrupt                                 */
  EXTI3_IRQn                  = 9,      /*!< EXTI Line3 Interrupt                                 */
  EXTI4_IRQn                  = 10,     /*!< EXTI Line4 Interrupt                                 */
  DMA1_Channel1_IRQn          = 11,     /*!< DMA1 Channel 1 global Interrupt                      */
  DMA1_Channel2_IRQn          = 12,     /*!< DMA1 Channel 2 global Interrupt                      */
  DMA1_Channel3_IRQn          = 13,     /*!< DMA1 Channel 3 global Interrupt                      */
  DMA1_Channel4_IRQn          = 14,     /*!< DMA1 Channel 4 global Interrupt                      */
  DMA1_Channel5_IRQn          = 15,     /*!< DMA1 Channel 5 global Interrupt                      */
  DMA1_Channel6_IRQn          = 16,     /*!< DMA1 Channel 6 global Interrupt                      */
  DMA1_Channel7_IRQn          = 17,     /*!< DMA1 Channel 7 global Interrupt                      */

#ifdef STM32F10X_LD
  ADC1_2_IRQn                 = 18,     /*!< ADC1 and ADC2 global Interrupt                       */
  USB_HP_CAN1_TX_IRQn         = 19,     /*!< USB Device High Priority or CAN1 TX Interrupts       */
  USB_LP_CAN1_RX0_IRQn        = 20,     /*!< USB Device Low Priority or CAN1 RX0 Interrupts       */
  CAN1_RX1_IRQn               = 21,     /*!< CAN1 RX1 Interrupt                                   */
  CAN1_SCE_IRQn               = 22,     /*!< CAN1 SCE Interrupt                                   */
  EXTI9_5_IRQn                = 23,     /*!< External Line[9:5] Interrupts                        */
  TIM1_BRK_IRQn               = 24,     /*!< TIM1 Break Interrupt                                 */
  TIM1_UP_IRQn                = 25,     /*!< TIM1 Update Interrupt                                */
  TIM1_TRG_COM_IRQn           = 26,     /*!< TIM1 Trigger and Commutation Interrupt               */
  TIM1_CC_IRQn                = 27,     /*!< TIM1 Capture Compare Interrupt                       */
  TIM2_IRQn                   = 28,     /*!< TIM2 global Interrupt                                */
  TIM3_IRQn                   = 29,     /*!< TIM3 global Interrupt                                */
  I2C1_EV_IRQn                = 31,     /*!< I2C1 Event Interrupt                                 */
  I2C1_ER_IRQn                = 32,     /*!< I2C1 Error Interrupt                                 */
  SPI1_IRQn                   = 35,     /*!< SPI1 global Interrupt                                */
  USART1_IRQn                 = 37,     /*!< USART1 global Interrupt                              */
  USART2_IRQn                 = 38,     /*!< USART2 global Interrupt                              */
  EXTI15_10_IRQn              = 40,     /*!< External Line[15:10] Interrupts                      */
  RTCAlarm_IRQn               = 41,     /*!< RTC Alarm through EXTI Line Interrupt                */
  USBWakeUp_IRQn              = 42      /*!< USB Device WakeUp from suspend through EXTI Line Interrupt */
#endif /* STM32F10X_LD */
} IRQn_Type;

Many manufactures will include a count item at the end of this (I usually add it if they don't), something like

   PERIPH_COUNT_IRQn = 43

It is not easy not being overwhelmed by all the information. More information often can lead to more confusion rather then more clarity.

Next Thread | Thread List | Previous Thread Start a Thread | Settings

  Arm logo
Important information

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies.

Change Settings

Privacy Policy Update

Arm’s Privacy Policy has been updated. By continuing to use our site, you consent to Arm’s Privacy Policy. Please review our Privacy Policy to learn more about our collection, use and transfers
of your data.