ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Среда
12 ноября
1553641 Топик полностью
klen (Сегодня, 00:57, просмотров: 76) ответил AlexG на Перенес в MounRiver Studio 2 (RISC-V) из IAR(ARM) старый проект на смеси C и C++, а конструкторы классов то и не вызываются. На сколько я понимаю, в startup от WCH не хватает вызова функции которая всё это делает. Где-бы взять нормальный полноценный startup для CH32V?
а че его брать то - давай сами напишем... 

ниже мой startup код для ch32v307


ловкость рук и никакого мошенства (асма... почти :)) камменты разжевывают этот простой вопрос до молекулярного состава.

едиственное что нужно знать извнешнего мира это то что С/С++ компиляторы код вызовов конструкторов и деструкторов ( компиллер оформляет их как массив совершенно бычных функции с сигнатурой void f(void) ) глобальных объектов и функций с атрибутом constructor помещают в массивы

preinit_array / init_array / fini_array - по ним нужно пройтись и вызвать все точки входа.



портянка программы :

reset_handler
         { system_init()
           crt_init()
           __machine_mode_init()
freertos_port_machine_mode_init(); mepc( __user_mode_entry); mret ----------------------------------------------------> __user_mode_entry } { вызов конструкторов из preinit_array __init() вызов конструкторов глобальных объектов С++ и фунций с аттрибутом ''constructor" из init_array __premain () main() вызов деструкторов из fini_array __fini() }



обработчик сброса reset_handler()



void __attribute__((used,naked)) reset_handler() { #ifdef __CRT_IMPL_GDB_DEALY__ // задержка после сброса, для обеспечения захвата отдажчиком GDB nop_while(__CRT_IMPL_GDB_DEALY__); #endif // установка глобального указателя gp( gnu_linker_global_pointer()) ; // установка указателя стека sp( gnu_linker_main_stack_end() ) ; // настройка конвейера процессора corecfg_t::val(0x1f); // установка вложенных прерываний и аппаратного стека intsysc_t::write(
intsysc_t::hardware_stack_t::enable, intsysc_t::interrupt_nesting_t::enable, intsysc_t::preemption_t::level4, intsysc_t::interrupt_enable_after_hpe_overflow_t::enable ); // глобальное разрешение прерываний, включение fpu mstatus_t::write( mstatus_t::global_interrupt_enable_t::enable, mstatus_t::interrupt_enable_state_befor_entering_t::enable, mstatus_t::fpu_status_t::dirty ) ; // установка таблицы векторов mtvec_t::write( mtvec_t::trap_address_mode_t::base_offset , mtvec_t::trap_jump_mode_t::address, static_cast<mtvec_t::trap_base_t>(reinterpret_cast<uint32_t>(reset_entry_point)) ); system_init(); crt_init(); __machine_mode_init() ; #ifdef __USE_FREERTOS__ // инициализация freertos, требующая machine mode freertos_port_machine_mode_init(); #endif // прыжок в user-mode c вызовом __user_mode_entry mepc( reinterpret_cast<void*>(__user_mode_entry)); mret(); }



функция инициализации system_init()

__ais__ void system_init()
{
      // TODO учесть разницу __CH32V30x_D8C__ vs __CH32V30x_D8__
      // вданный момент все сделано для   __CH32V30x_D8C__

      // не экономим электричество
      extc.ldo_trim_1dot0v();

      rcc.hsi_enable();       // включение hsi
      rcc.hsi_ready_wait();   // ожидание запуска hsi
      rcc.sys_clock_source_hsi();

      rcc.clock_config0.modify(
          rcc_t::clock_config0_t::sys_clock_source_t::hsi,
      	  rcc_t::clock_config0_t::ahb_clock_prescaler_t::div1,
		  rcc_t::clock_config0_t::apb2_clock_prescaler_t::div1,
      	  rcc_t::clock_config0_t::adc_clock_prescaler_t::div2,
		  rcc_t::clock_config0_t::pll_hse_div_t::div1,
      	  rcc_t::clock_config0_t::mco_t::disconnect
      			              );

      rcc.clock_control.modify(
          rcc_t::clock_control_t::hse_t::disable,
      	  rcc_t::clock_control_t::hse_bypass_t::disable,
      	  rcc_t::clock_control_t::clock_security_system_t::disable,
      	  rcc_t::clock_control_t::pll_t::disable
#if defined __CH32V30x_D8C__ |__CH32V31x_D8C__
		  ,rcc_t::clock_control_t::pll2_t::disable,
		   rcc_t::clock_control_t::pll3_t::disable
#endif
                                );
        // выключение прерываний
        rcc.clock_interrupt.val(0);
        // сброс флагов прерываний
        rcc.interrupt_flags_clear();

        extern const rcc_t::system_init_profile_t system_init_profile ;

        // установка параметров flash
// TODO       flash_control.latency(system_init_profile.flash_latency);

        // установка делителя клока ahb/apb1/apb2

        rcc.ahb_clock_prescaler(system_init_profile.ahb_clock_prescaler);
        rcc.apb1_clock_prescaler(system_init_profile.apb1_clock_prescaler);
        rcc.apb2_clock_prescaler(system_init_profile.apb2_clock_prescaler);

        // установка системного клока
        switch( system_init_profile.sys_clock )
          {
             case rcc_t::system_init_profile_t::sys_clock_t::hsi :
            	 extc.pll_hsi_div(system_init_profile.pll_hsi_div);
            	 rcc.sys_clock_hsi();
                 break;
             case rcc_t::system_init_profile_t::sys_clock_t::hse :
                 rcc.sys_clock_hse();
                 rcc.clock_security_system(system_init_profile.clock_security_system) ;
                 break;
             case rcc_t::system_init_profile_t::sys_clock_t::hsi_pll :
            	 extc.pll_hsi_div(system_init_profile.pll_hsi_div);
                 rcc.pll_mul(system_init_profile.pll_mul);
                 rcc.sys_clock_hsi_pll();
                 break;
             case rcc_t::system_init_profile_t::sys_clock_t::hse_pll :
            	 rcc.pll_hse_div(system_init_profile.pll_hse_div);
            	 rcc.pll_mul(system_init_profile.pll_mul);
            	 rcc.pll_div(system_init_profile.pll_div);
            	 rcc.sys_clock_hse_pll();
            	 rcc.clock_security_system(system_init_profile.clock_security_system) ;
            	 break;
#if defined __CH32V30x_D8C__ |__CH32V31x_D8C__
             case rcc_t::system_init_profile_t::sys_clock_t::hse_pll2_pll :
            	 rcc.pll_hse_div(system_init_profile.pll_hse_div);
            	 rcc.pll_mul(system_init_profile.pll_mul);
            	 rcc.pll_div(system_init_profile.pll_div);
            	 rcc.pll2_mul(system_init_profile.pll2_mul);
            	 rcc.pll2_div(system_init_profile.pll2_div);
            	 rcc.sys_clock_hse_pll2_pll();
            	 rcc.clock_security_system(system_init_profile.clock_security_system) ;
            	 break;
#endif
             default:
                std::__throw_invalid_argument(0);
          }
}


функция инициализации CRT - crt_init();


__ais__ constexpr auto crt_init()
{
  // инициализация секции данных .data
  std::copy(gnu_linker_data_load_start(), // cppcheck-suppress mismatchingContainers
			  gnu_linker_data_load_start() + (gnu_linker_data_end() - gnu_linker_data_start()),
			  const_cast <uint32_t*>(gnu_linker_data_start()));

  // инициализация секции данных .bss
  std::fill(const_cast <uint32_t*>(gnu_linker_bss_start()), // cppcheck-suppress mismatchingContainers
		    const_cast <uint32_t*>(gnu_linker_bss_end()),
                   0U);


  #ifdef __CRT_IMPL_MAIN_STACK_STATE_INFO__
     // маскирования стека маской состяния, маска определена в gnu_linker.h
     std::fill(const_cast <uint32_t*>(gnu_linker_main_stack_start()), // cppcheck-suppress mismatchingContainers
  		       static_cast <uint32_t*>(sp()),
			  __CRT_IMPL_MAIN_STACK_STATE_INFO_MASK__);
  #endif // __CRT_IMPL_MAIN_STACK_STATE_INFO__
}


функция инициализации __user_mode_entry()

static constexpr __attribute__((noreturn,naked)) void __user_mode_entry()
{
  // вызов конструкторов глобальных объектов и функций с атрибутом constructor
  #ifndef __CRT_IMPL_PREINIT_ARRAY_DISABLE__
     std::for_each( gnu_linker_preinit_array_start(),
    		        gnu_linker_preinit_array_end(),
                    [](void (*pf)(void)) {(pf)();});
  #endif // __CRT_IMPL_PREINIT_ARRAY_DISABLE__
   
  void __init (void);
  __init ();

  std::for_each( gnu_linker_init_array_start(),
		         gnu_linker_init_array_end(),
                     [](void (*pf)(void)) {(pf)();});


 
  // предварительыне действия в режиме user перед вызововом main
  void __premain (void);
  __premain ();
  // основная программа
  main();

  #ifdef __CRT_IMPL_FINI__
     // вызов деструкторов глобальных объектов и функций с атрибутом destructor
     std::for_each( gnu_linker_fini_array_start(),
    		        gnu_linker_fini_array_end(),
                    [](void (*pf)(void)) {(pf)();});

     void __fini (void);
     __fini();
  #endif

  /* __user_mode_entry не подразумевет зацикливание при выходе из main. в случае необходимости
     такого поведения, блокировка циклом или иным способом должна быть выполнена в конце main() или
     определением дефайна __CRT_IMPL_FINI__ с реализацией данных мер в __fini()

     в случае отсутствия блокировки в main() или __fini(), произходит naked выход из
     __user_mode_entry c возвратом к точке входа __user_mode_entry()
  */
}