ODrive学习笔记二:main.cpp学习

avatar
作者
猴君
阅读量:2

系列文章目录

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

提示:这里可以添加本文要记录的大概内容:


提示:以下是本篇文章正文内容,下面案例可供参考

一、代码解析

1.FreeRTOS配置

代码如下(示例):

#define configUSE_PREEMPTION                     1 #define configSUPPORT_STATIC_ALLOCATION          0 #define configSUPPORT_DYNAMIC_ALLOCATION         1 #define configUSE_IDLE_HOOK                      1 #define configUSE_TICK_HOOK                      0 #define configCPU_CLOCK_HZ                       ( SystemCoreClock ) #define configTICK_RATE_HZ                       ((TickType_t)1000) #define configMAX_PRIORITIES                     ( 7 ) #define configMINIMAL_STACK_SIZE                 ((uint16_t)128) #define configTOTAL_HEAP_SIZE                    ((size_t)65536) #define configMAX_TASK_NAME_LEN                  ( 16 ) #define configUSE_16_BIT_TICKS                   0 #define configUSE_MUTEXES                        1 #define configQUEUE_REGISTRY_SIZE                8 #define configCHECK_FOR_STACK_OVERFLOW           1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION  1 

这里其实跟KEIL或者C版本的代码时一样的,找到SystemCoreClock 的定义,是160MHz,也就是系统的主频。然后总的堆栈大小是64K,并且注意一下这段堆栈的分配。

#if defined(STM32F405xx) // Place FreeRTOS heap in core coupled memory for better performance __attribute__((section(".ccmram"))) uint8_t ucHeap[configTOTAL_HEAP_SIZE]; #endif  /* Specify the memory areas */ MEMORY { RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K CCMRAM (rw)      : ORIGIN = 0x10000000, LENGTH = 64K FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 768K NVM (r)         : ORIGIN = 0x80C0000, LENGTH = 256K } 

405的手册没仔细看,但是RAM也是分了两个区,RAM1和RAM2。其中RAM2也就是CCMRAM。main.cpp中通过一段声明将ucHeap分配到了这段RAM空间,目的应该是有更快的访问速度,但是印象中这段RAM不能用于DMA传输。

另外没有在配置里面看到软件定时器的设置,可能不需要吧。

2.配置操作

main.cpp的前半部分都是配置的一些操作接口。比如读取、擦除、写入、生效等操作。不用太细看。

4.进DFU模式

 uint32_t _reboot_cookie __attribute__ ((section (".noinit"))); //进入DFU模式,禁止中断  写入升级标志 并且调用NVIC Reset void ODrive::enter_dfu_mode() {     if ((hw_version_major_ == 3) && (hw_version_minor_ >= 5)) {         __asm volatile ("CPSID I\n\t":::"memory"); // disable interrupts         _reboot_cookie = 0xDEADBEEF;         NVIC_SystemReset();     } else {         /*         * DFU mode is only allowed on board version >= 3.5 because it can burn         * the brake resistor FETs on older boards.         * If you really want to use it on an older board, add 3.3k pull-down resistors         * to the AUX_L and AUX_H signals and _only then_ uncomment these lines.         */         //__asm volatile ("CPSID I\n\t":::"memory"); // disable interrupts         //_reboot_cookie = 0xDEADFE75;         //NVIC_SystemReset();     } } 

也比较简单,就是对_reboot_cookie这个变量进行赋值

5.错误操作

包含错误检测/错误清除/获取驱动异常等接口。

bool ODrive::any_error() { uint64_t ODrive::get_drv_fault() { void ODrive::clear_errors() { 

6.钩子函数

包含错误检测/错误清除/获取驱动异常等接口。
这里的stackoverflow 还做了一些保护动作 对刹车电阻有一些措施

 void vApplicationStackOverflowHook(xTaskHandle *pxTask, signed portCHAR *pcTaskName) {     for(auto& axis: axes){         axis.motor_.disarm();     }     safety_critical_disarm_brake_resistor();     for (;;); // TODO: safe action }  void vApplicationIdleHook(void) {     if (odrv.system_stats_.fully_booted) {         odrv.system_stats_.uptime = xTaskGetTickCount();         odrv.system_stats_.min_heap_space = xPortGetMinimumEverFreeHeapSize();          uint32_t min_stack_space[AXIS_COUNT];         std::transform(axes.begin(), axes.end(), std::begin(min_stack_space), [](auto& axis) { return uxTaskGetStackHighWaterMark(axis.thread_id_) * sizeof(StackType_t); });         odrv.system_stats_.max_stack_usage_axis = axes[0].stack_size_ - *std::min_element(std::begin(min_stack_space), std::end(min_stack_space));         odrv.system_stats_.max_stack_usage_usb = stack_size_usb_thread - uxTaskGetStackHighWaterMark(usb_thread) * sizeof(StackType_t);         odrv.system_stats_.max_stack_usage_uart = stack_size_uart_thread - uxTaskGetStackHighWaterMark(uart_thread) * sizeof(StackType_t);         odrv.system_stats_.max_stack_usage_startup = stack_size_default_task - uxTaskGetStackHighWaterMark(defaultTaskHandle) * sizeof(StackType_t);         odrv.system_stats_.max_stack_usage_can = odrv.can_.stack_size_ - uxTaskGetStackHighWaterMark(odrv.can_.thread_id_) * sizeof(StackType_t);         odrv.system_stats_.max_stack_usage_analog =  stack_size_analog_thread - uxTaskGetStackHighWaterMark(analog_thread) * sizeof(StackType_t);          odrv.system_stats_.stack_size_axis = axes[0].stack_size_;         odrv.system_stats_.stack_size_usb = stack_size_usb_thread;         odrv.system_stats_.stack_size_uart = stack_size_uart_thread;         odrv.system_stats_.stack_size_startup = stack_size_default_task;         odrv.system_stats_.stack_size_can = odrv.can_.stack_size_;         odrv.system_stats_.stack_size_analog = stack_size_analog_thread;          odrv.system_stats_.prio_axis = osThreadGetPriority(axes[0].thread_id_);         odrv.system_stats_.prio_usb = osThreadGetPriority(usb_thread);         odrv.system_stats_.prio_uart = osThreadGetPriority(uart_thread);         odrv.system_stats_.prio_startup = osThreadGetPriority(defaultTaskHandle);         odrv.system_stats_.prio_can = osThreadGetPriority(odrv.can_.thread_id_);         odrv.system_stats_.prio_analog = osThreadGetPriority(analog_thread);          status_led_controller.update();     } } } 

7.回调函数

void ODrive::sampling_cb() { 

sampling_cb应该就是用来更新编码器数值的。

void ODrive::control_loop_cb(uint32_t timestamp) { 

control_loop_cb里内容比较多一点

MEASURE_TIME(task_times_.control_loop_misc) {         // Reset all output ports so that we are certain about the freshness of         // all values that we use.         // If we forget to reset a value here the worst that can happen is that         // this safety check doesn't work.         // TODO: maybe we should add a check to output ports that prevents         // double-setting the value.         for (auto& axis: axes) {             axis.acim_estimator_.slip_vel_.reset();             axis.acim_estimator_.stator_phase_vel_.reset();             axis.acim_estimator_.stator_phase_.reset();             axis.controller_.torque_output_.reset();             axis.encoder_.phase_.reset();             axis.encoder_.phase_vel_.reset();             axis.encoder_.pos_estimate_.reset();             axis.encoder_.vel_estimate_.reset();             axis.encoder_.pos_circular_.reset();             axis.motor_.Vdq_setpoint_.reset();             axis.motor_.Idq_setpoint_.reset();             axis.open_loop_controller_.Idq_setpoint_.reset();             axis.open_loop_controller_.Vdq_setpoint_.reset();             axis.open_loop_controller_.phase_.reset();             axis.open_loop_controller_.phase_vel_.reset();             axis.open_loop_controller_.total_distance_.reset();             axis.sensorless_estimator_.phase_.reset();             axis.sensorless_estimator_.phase_vel_.reset();             axis.sensorless_estimator_.vel_estimate_.reset();         }          uart_poll();         odrv.oscilloscope_.update();     } 

这里会定期让系统各个输出复位。包括串口的操作,刷新缓存 启动接收。

8.获取外设状态

uint32_t ODrive::get_interrupt_status(int32_t irqn) { 
uint32_t ODrive::get_dma_status(uint8_t stream_num) { 
uint32_t ODrive::get_gpio_states() { 

9.rtos_main

接口进来之后先对外设进行初始化

    // Init USB device     MX_USB_DEVICE_Init();       // Start ADC for temperature measurements and user measurements     start_general_purpose_adc();      //osDelay(100);     // Init communications (this requires the axis objects to be constructed)     init_communication();      // Start pwm-in compare modules     // must happen after communication is initialized     pwm0_input.init(); 

USB/ADC/COMM(串口 I2C CAN)/PWM。这些系统级的。

for(auto& axis : axes){ 

之后对每一路电机进行初始化

初始化完成之后会用2S时间对电机电流进行采集校准。

之后会启动各电机的各类任务。之后启动Freertos 完成。

9.main函数

    uint32_t uuid0 = *(uint32_t *)(UID_BASE + 0);     uint32_t uuid1 = *(uint32_t *)(UID_BASE + 4);     uint32_t uuid2 = *(uint32_t *)(UID_BASE + 8);     uint32_t uuid_mixed_part = uuid0 + uuid2;     serial_number = ((uint64_t)uuid_mixed_part << 16) | (uint64_t)(uuid1 >> 16) 
  1. 首先获取MCU的UID。
  2. 然后系统初始化,时钟之类。
  3. 再就是获取参数配置并应用。
  4. 板载初始化 外设的初始化,硬件驱动层
  5. GPIO 初始化,好像引用的也是HAL库。。。
  6. 信号量 队列的初始化
    7、创建 rtos_main进程
    8、启动Freertos

总结

相对来说main.cpp内容还好,大部分是一些系统需要的功能模块和完成初始化的相关的工作。

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!