1 Star 0 Fork 2

lelongGITEE/bldc

forked from zhanshenrui/bldc 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
comm_can.c 16.71 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
/*
Copyright 2016 Benjamin Vedder benjamin@vedder.se
This file is part of the VESC firmware.
The VESC firmware is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
The VESC firmware is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <math.h>
#include "comm_can.h"
#include "ch.h"
#include "hal.h"
#include "stm32f4xx_conf.h"
#include "datatypes.h"
#include "buffer.h"
#include "mc_interface.h"
#include "timeout.h"
#include "commands.h"
#include "app.h"
#include "crc.h"
#include "packet.h"
// Settings
#define CANDx CAND1
#define RX_FRAMES_SIZE 100
#define RX_BUFFER_SIZE PACKET_MAX_PL_LEN
// Threads
static THD_WORKING_AREA(cancom_read_thread_wa, 512);
static THD_WORKING_AREA(cancom_process_thread_wa, 4096);
static THD_WORKING_AREA(cancom_status_thread_wa, 1024);
static THD_FUNCTION(cancom_read_thread, arg);
static THD_FUNCTION(cancom_status_thread, arg);
static THD_FUNCTION(cancom_process_thread, arg);
// Variables
static can_status_msg stat_msgs[CAN_STATUS_MSGS_TO_STORE];
static mutex_t can_mtx;
static uint8_t rx_buffer[RX_BUFFER_SIZE];
static unsigned int rx_buffer_last_id;
static CANRxFrame rx_frames[RX_FRAMES_SIZE];
static int rx_frame_read;
static int rx_frame_write;
static thread_t *process_tp;
/*
* 500KBaud, automatic wakeup, automatic recover
* from abort mode.
* See section 22.7.7 on the STM32 reference manual.
*/
static CANConfig cancfg = {
CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_TXFP,
CAN_BTR_SJW(3) | CAN_BTR_TS2(2) |
CAN_BTR_TS1(9) | CAN_BTR_BRP(5)
};
// Private functions
static void send_packet_wrapper(unsigned char *data, unsigned int len);
static void set_timing(int brp, int ts1, int ts2);
// Function pointers
static void(*sid_callback)(uint32_t id, uint8_t *data, uint8_t len) = 0;
void comm_can_init(void) {
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
stat_msgs[i].id = -1;
}
rx_frame_read = 0;
rx_frame_write = 0;
chMtxObjectInit(&can_mtx);
palSetPadMode(GPIOB, 8,
PAL_MODE_ALTERNATE(GPIO_AF_CAN1) |
PAL_STM32_OTYPE_PUSHPULL |
PAL_STM32_OSPEED_MID1);
palSetPadMode(GPIOB, 9,
PAL_MODE_ALTERNATE(GPIO_AF_CAN1) |
PAL_STM32_OTYPE_PUSHPULL |
PAL_STM32_OSPEED_MID1);
canStart(&CANDx, &cancfg);
chThdCreateStatic(cancom_read_thread_wa, sizeof(cancom_read_thread_wa), NORMALPRIO + 1,
cancom_read_thread, NULL);
chThdCreateStatic(cancom_status_thread_wa, sizeof(cancom_status_thread_wa), NORMALPRIO,
cancom_status_thread, NULL);
chThdCreateStatic(cancom_process_thread_wa, sizeof(cancom_process_thread_wa), NORMALPRIO,
cancom_process_thread, NULL);
}
void comm_can_set_baud(CAN_BAUD baud) {
switch (baud) {
case CAN_BAUD_125K: set_timing(15, 14, 4); break;
case CAN_BAUD_250K: set_timing(7, 14, 4); break;
case CAN_BAUD_500K: set_timing(5, 9, 2); break;
case CAN_BAUD_1M: set_timing(2, 9, 2); break;
default: break;
}
}
static THD_FUNCTION(cancom_read_thread, arg) {
(void)arg;
chRegSetThreadName("CAN");
event_listener_t el;
CANRxFrame rxmsg;
chEvtRegister(&CANDx.rxfull_event, &el, 0);
while(!chThdShouldTerminateX()) {
if (chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(10)) == 0) {
continue;
}
msg_t result = canReceive(&CANDx, CAN_ANY_MAILBOX, &rxmsg, TIME_IMMEDIATE);
while (result == MSG_OK) {
rx_frames[rx_frame_write++] = rxmsg;
if (rx_frame_write == RX_FRAMES_SIZE) {
rx_frame_write = 0;
}
chEvtSignal(process_tp, (eventmask_t) 1);
result = canReceive(&CANDx, CAN_ANY_MAILBOX, &rxmsg, TIME_IMMEDIATE);
}
}
chEvtUnregister(&CANDx.rxfull_event, &el);
}
static THD_FUNCTION(cancom_process_thread, arg) {
(void)arg;
chRegSetThreadName("Cancom process");
process_tp = chThdGetSelfX();
int32_t ind = 0;
unsigned int rxbuf_len;
unsigned int rxbuf_ind;
uint8_t crc_low;
uint8_t crc_high;
bool commands_send;
for(;;) {
chEvtWaitAny((eventmask_t) 1);
while (rx_frame_read != rx_frame_write) {
CANRxFrame rxmsg = rx_frames[rx_frame_read++];
if (rxmsg.IDE == CAN_IDE_EXT) {
uint8_t id = rxmsg.EID & 0xFF;
CAN_PACKET_ID cmd = rxmsg.EID >> 8;
can_status_msg *stat_tmp;
if (id == 255 || id == app_get_configuration()->controller_id) {
switch (cmd) {
case CAN_PACKET_SET_DUTY:
ind = 0;
mc_interface_set_duty(buffer_get_float32(rxmsg.data8, 1e5, &ind));
timeout_reset();
break;
case CAN_PACKET_SET_CURRENT:
ind = 0;
mc_interface_set_current(buffer_get_float32(rxmsg.data8, 1e3, &ind));
timeout_reset();
break;
case CAN_PACKET_SET_CURRENT_BRAKE:
ind = 0;
mc_interface_set_brake_current(buffer_get_float32(rxmsg.data8, 1e3, &ind));
timeout_reset();
break;
case CAN_PACKET_SET_RPM:
ind = 0;
mc_interface_set_pid_speed(buffer_get_float32(rxmsg.data8, 1e0, &ind));
timeout_reset();
break;
case CAN_PACKET_SET_POS:
ind = 0;
mc_interface_set_pid_pos(buffer_get_float32(rxmsg.data8, 1e6, &ind));
timeout_reset();
break;
case CAN_PACKET_FILL_RX_BUFFER:
memcpy(rx_buffer + rxmsg.data8[0], rxmsg.data8 + 1, rxmsg.DLC - 1);
break;
case CAN_PACKET_FILL_RX_BUFFER_LONG:
rxbuf_ind = (unsigned int)rxmsg.data8[0] << 8;
rxbuf_ind |= rxmsg.data8[1];
if (rxbuf_ind < RX_BUFFER_SIZE) {
memcpy(rx_buffer + rxbuf_ind, rxmsg.data8 + 2, rxmsg.DLC - 2);
}
break;
case CAN_PACKET_PROCESS_RX_BUFFER:
ind = 0;
rx_buffer_last_id = rxmsg.data8[ind++];
commands_send = rxmsg.data8[ind++];
rxbuf_len = (unsigned int)rxmsg.data8[ind++] << 8;
rxbuf_len |= (unsigned int)rxmsg.data8[ind++];
if (rxbuf_len > RX_BUFFER_SIZE) {
break;
}
crc_high = rxmsg.data8[ind++];
crc_low = rxmsg.data8[ind++];
if (crc16(rx_buffer, rxbuf_len)
== ((unsigned short) crc_high << 8
| (unsigned short) crc_low)) {
if (commands_send) {
commands_send_packet(rx_buffer, rxbuf_len);
} else {
commands_set_send_func(send_packet_wrapper);
commands_process_packet(rx_buffer, rxbuf_len);
}
}
break;
case CAN_PACKET_PROCESS_SHORT_BUFFER:
ind = 0;
rx_buffer_last_id = rxmsg.data8[ind++];
commands_send = rxmsg.data8[ind++];
if (commands_send) {
commands_send_packet(rxmsg.data8 + ind, rxmsg.DLC - ind);
} else {
commands_set_send_func(send_packet_wrapper);
commands_process_packet(rxmsg.data8 + ind, rxmsg.DLC - ind);
}
break;
case CAN_PACKET_SET_CURRENT_REL:
ind = 0;
mc_interface_set_current_rel(buffer_get_float32(rxmsg.data8, 1e5, &ind));
timeout_reset();
break;
case CAN_PACKET_SET_CURRENT_BRAKE_REL:
ind = 0;
mc_interface_set_brake_current_rel(buffer_get_float32(rxmsg.data8, 1e5, &ind));
timeout_reset();
break;
case CAN_PACKET_SET_CURRENT_HANDBRAKE:
ind = 0;
mc_interface_set_handbrake(buffer_get_float32(rxmsg.data8, 1e3, &ind));
timeout_reset();
break;
case CAN_PACKET_SET_CURRENT_HANDBRAKE_REL:
ind = 0;
mc_interface_set_handbrake_rel(buffer_get_float32(rxmsg.data8, 1e5, &ind));
timeout_reset();
break;
default:
break;
}
}
switch (cmd) {
case CAN_PACKET_STATUS:
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
stat_tmp = &stat_msgs[i];
if (stat_tmp->id == id || stat_tmp->id == -1) {
ind = 0;
stat_tmp->id = id;
stat_tmp->rx_time = chVTGetSystemTime();
stat_tmp->rpm = (float)buffer_get_int32(rxmsg.data8, &ind);
stat_tmp->current = (float)buffer_get_int16(rxmsg.data8, &ind) / 10.0;
stat_tmp->duty = (float)buffer_get_int16(rxmsg.data8, &ind) / 1000.0;
break;
}
}
break;
default:
break;
}
} else {
if (sid_callback) {
sid_callback(rxmsg.SID, rxmsg.data8, rxmsg.DLC);
}
}
if (rx_frame_read == RX_FRAMES_SIZE) {
rx_frame_read = 0;
}
}
}
}
static THD_FUNCTION(cancom_status_thread, arg) {
(void)arg;
chRegSetThreadName("CAN status");
for(;;) {
if (app_get_configuration()->send_can_status) {
// Send status message
int32_t send_index = 0;
uint8_t buffer[8];
buffer_append_int32(buffer, (int32_t)mc_interface_get_rpm(), &send_index);
buffer_append_int16(buffer, (int16_t)(mc_interface_get_tot_current() * 10.0), &send_index);
buffer_append_int16(buffer, (int16_t)(mc_interface_get_duty_cycle_now() * 1000.0), &send_index);
comm_can_transmit_eid(app_get_configuration()->controller_id |
((uint32_t)CAN_PACKET_STATUS << 8), buffer, send_index);
}
systime_t sleep_time = CH_CFG_ST_FREQUENCY / app_get_configuration()->send_can_status_rate_hz;
if (sleep_time == 0) {
sleep_time = 1;
}
chThdSleep(sleep_time);
}
}
void comm_can_transmit_eid(uint32_t id, uint8_t *data, uint8_t len) {
if (len > 8) {
len = 8;
}
#if CAN_ENABLE
CANTxFrame txmsg;
txmsg.IDE = CAN_IDE_EXT;
txmsg.EID = id;
txmsg.RTR = CAN_RTR_DATA;
txmsg.DLC = len;
memcpy(txmsg.data8, data, len);
chMtxLock(&can_mtx);
canTransmit(&CANDx, CAN_ANY_MAILBOX, &txmsg, MS2ST(20));
chMtxUnlock(&can_mtx);
#else
(void)id;
(void)data;
(void)len;
#endif
}
void comm_can_transmit_sid(uint32_t id, uint8_t *data, uint8_t len) {
if (len > 8) {
len = 8;
}
#if CAN_ENABLE
CANTxFrame txmsg;
txmsg.IDE = CAN_IDE_STD;
txmsg.SID = id;
txmsg.RTR = CAN_RTR_DATA;
txmsg.DLC = len;
memcpy(txmsg.data8, data, len);
chMtxLock(&can_mtx);
canTransmit(&CANDx, CAN_ANY_MAILBOX, &txmsg, MS2ST(20));
chMtxUnlock(&can_mtx);
#else
(void)id;
(void)data;
(void)len;
#endif
}
/**
* Set function to be called when standard CAN frames are received.
*
* @param p_func
* Pointer to the function.
*/
void comm_can_set_sid_rx_callback(void (*p_func)(uint32_t id, uint8_t *data, uint8_t len)) {
sid_callback = p_func;
}
/**
* Send a buffer up to RX_BUFFER_SIZE bytes as fragments. If the buffer is 6 bytes or less
* it will be sent in a single CAN frame, otherwise it will be split into
* several frames.
*
* @param controller_id
* The controller id to send to.
*
* @param data
* The payload.
*
* @param len
* The payload length.
*
* @param send
* If true, this packet will be passed to the send function of commands.
* Otherwise, it will be passed to the process function.
*/
void comm_can_send_buffer(uint8_t controller_id, uint8_t *data, unsigned int len, bool send) {
uint8_t send_buffer[8];
if (len <= 6) {
uint32_t ind = 0;
send_buffer[ind++] = app_get_configuration()->controller_id;
send_buffer[ind++] = send;
memcpy(send_buffer + ind, data, len);
ind += len;
comm_can_transmit_eid(controller_id |
((uint32_t)CAN_PACKET_PROCESS_SHORT_BUFFER << 8), send_buffer, ind);
} else {
unsigned int end_a = 0;
for (unsigned int i = 0;i < len;i += 7) {
if (i > 255) {
break;
}
end_a = i + 7;
uint8_t send_len = 7;
send_buffer[0] = i;
if ((i + 7) <= len) {
memcpy(send_buffer + 1, data + i, send_len);
} else {
send_len = len - i;
memcpy(send_buffer + 1, data + i, send_len);
}
comm_can_transmit_eid(controller_id |
((uint32_t)CAN_PACKET_FILL_RX_BUFFER << 8), send_buffer, send_len + 1);
}
for (unsigned int i = end_a;i < len;i += 6) {
uint8_t send_len = 6;
send_buffer[0] = i >> 8;
send_buffer[1] = i & 0xFF;
if ((i + 6) <= len) {
memcpy(send_buffer + 2, data + i, send_len);
} else {
send_len = len - i;
memcpy(send_buffer + 2, data + i, send_len);
}
comm_can_transmit_eid(controller_id |
((uint32_t)CAN_PACKET_FILL_RX_BUFFER_LONG << 8), send_buffer, send_len + 2);
}
uint32_t ind = 0;
send_buffer[ind++] = app_get_configuration()->controller_id;
send_buffer[ind++] = send;
send_buffer[ind++] = len >> 8;
send_buffer[ind++] = len & 0xFF;
unsigned short crc = crc16(data, len);
send_buffer[ind++] = (uint8_t)(crc >> 8);
send_buffer[ind++] = (uint8_t)(crc & 0xFF);
comm_can_transmit_eid(controller_id |
((uint32_t)CAN_PACKET_PROCESS_RX_BUFFER << 8), send_buffer, ind++);
}
}
void comm_can_set_duty(uint8_t controller_id, float duty) {
int32_t send_index = 0;
uint8_t buffer[4];
buffer_append_int32(buffer, (int32_t)(duty * 100000.0), &send_index);
comm_can_transmit_eid(controller_id |
((uint32_t)CAN_PACKET_SET_DUTY << 8), buffer, send_index);
}
void comm_can_set_current(uint8_t controller_id, float current) {
int32_t send_index = 0;
uint8_t buffer[4];
buffer_append_int32(buffer, (int32_t)(current * 1000.0), &send_index);
comm_can_transmit_eid(controller_id |
((uint32_t)CAN_PACKET_SET_CURRENT << 8), buffer, send_index);
}
void comm_can_set_current_brake(uint8_t controller_id, float current) {
int32_t send_index = 0;
uint8_t buffer[4];
buffer_append_int32(buffer, (int32_t)(current * 1000.0), &send_index);
comm_can_transmit_eid(controller_id |
((uint32_t)CAN_PACKET_SET_CURRENT_BRAKE << 8), buffer, send_index);
}
void comm_can_set_rpm(uint8_t controller_id, float rpm) {
int32_t send_index = 0;
uint8_t buffer[4];
buffer_append_int32(buffer, (int32_t)rpm, &send_index);
comm_can_transmit_eid(controller_id |
((uint32_t)CAN_PACKET_SET_RPM << 8), buffer, send_index);
}
void comm_can_set_pos(uint8_t controller_id, float pos) {
int32_t send_index = 0;
uint8_t buffer[4];
buffer_append_int32(buffer, (int32_t)(pos * 1000000.0), &send_index);
comm_can_transmit_eid(controller_id |
((uint32_t)CAN_PACKET_SET_POS << 8), buffer, send_index);
}
/**
* Set current relative to the minimum and maximum current limits.
*
* @param controller_id
* The ID of the VESC to set the current on.
*
* @param current_rel
* The relative current value, range [-1.0 1.0]
*/
void comm_can_set_current_rel(uint8_t controller_id, float current_rel) {
int32_t send_index = 0;
uint8_t buffer[4];
buffer_append_float32(buffer, current_rel, 1e5, &send_index);
comm_can_transmit_eid(controller_id |
((uint32_t)CAN_PACKET_SET_CURRENT_REL << 8), buffer, send_index);
}
/**
* Set brake current relative to the minimum current limit.
*
* @param controller_id
* The ID of the VESC to set the current on.
*
* @param current_rel
* The relative current value, range [0.0 1.0]
*/
void comm_can_set_current_brake_rel(uint8_t controller_id, float current_rel) {
int32_t send_index = 0;
uint8_t buffer[4];
buffer_append_float32(buffer, current_rel, 1e5, &send_index);
comm_can_transmit_eid(controller_id |
((uint32_t)CAN_PACKET_SET_CURRENT_BRAKE_REL << 8), buffer, send_index);
}
/**
* Set handbrake current.
*
* @param controller_id
* The ID of the VESC to set the handbrake current on.
*
* @param current_rel
* The handbrake current value
*/
void comm_can_set_handbrake(uint8_t controller_id, float current) {
int32_t send_index = 0;
uint8_t buffer[4];
buffer_append_float32(buffer, current, 1e3, &send_index);
comm_can_transmit_eid(controller_id |
((uint32_t)CAN_PACKET_SET_CURRENT_HANDBRAKE << 8), buffer, send_index);
}
/**
* Set handbrake current relative to the minimum current limit.
*
* @param controller_id
* The ID of the VESC to set the handbrake current on.
*
* @param current_rel
* The relative handbrake current value, range [0.0 1.0]
*/
void comm_can_set_handbrake_rel(uint8_t controller_id, float current_rel) {
int32_t send_index = 0;
uint8_t buffer[4];
buffer_append_float32(buffer, current_rel, 1e5, &send_index);
comm_can_transmit_eid(controller_id |
((uint32_t)CAN_PACKET_SET_CURRENT_HANDBRAKE_REL << 8), buffer, send_index);
}
/**
* Get status message by index.
*
* @param index
* Index in the array
*
* @return
* The message or 0 for an invalid index.
*/
can_status_msg *comm_can_get_status_msg_index(int index) {
if (index < CAN_STATUS_MSGS_TO_STORE) {
return &stat_msgs[index];
} else {
return 0;
}
}
/**
* Get status message by id.
*
* @param id
* Id of the controller that sent the status message.
*
* @return
* The message or 0 for an invalid id.
*/
can_status_msg *comm_can_get_status_msg_id(int id) {
for (int i = 0;i < CAN_STATUS_MSGS_TO_STORE;i++) {
if (stat_msgs[i].id == id) {
return &stat_msgs[i];
}
}
return 0;
}
static void send_packet_wrapper(unsigned char *data, unsigned int len) {
comm_can_send_buffer(rx_buffer_last_id, data, len, true);
}
static void set_timing(int brp, int ts1, int ts2) {
brp &= 0b1111111111;
ts1 &= 0b1111;
ts2 &= 0b111;
cancfg.btr = CAN_BTR_SJW(3) | CAN_BTR_TS2(ts2) |
CAN_BTR_TS1(ts1) | CAN_BTR_BRP(brp);
canStop(&CANDx);
canStart(&CANDx, &cancfg);
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/lelongz/bldc.git
git@gitee.com:lelongz/bldc.git
lelongz
bldc
bldc
master

搜索帮助

0d507c66 1850385 C8b1a773 1850385