自学内容网 自学内容网

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

系列文章目录

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 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内容还好,大部分是一些系统需要的功能模块和完成初始化的相关的工作。


原文地址:https://blog.csdn.net/lunzilx/article/details/140395498

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!