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)
- 首先获取MCU的UID。
- 然后系统初始化,时钟之类。
- 再就是获取参数配置并应用。
- 板载初始化 外设的初始化,硬件驱动层
- GPIO 初始化,好像引用的也是HAL库。。。
- 信号量 队列的初始化
7、创建 rtos_main进程
8、启动Freertos
总结
相对来说main.cpp内容还好,大部分是一些系统需要的功能模块和完成初始化的相关的工作。
原文地址:https://blog.csdn.net/lunzilx/article/details/140395498
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!