初始化
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
#include "adc.h"
|
||||
#include <stdint.h>
|
||||
#include "math.h"
|
||||
|
||||
constexpr float ERROR_ADC_VAL = 255.0f;
|
||||
constexpr float ADC_SCALE = 3.3f / 4096.0f;
|
||||
constexpr float TEMP_FACTOR = 1000.0f / 4.3f;
|
||||
constexpr float VCC_FACTOR = 11.0f;
|
||||
constexpr float CURRENT_FACTOR = 1.0f / 50.0f * 100.0f;
|
||||
constexpr float MAX_TEMP = 150.0f;
|
||||
constexpr float MIN_TEMP = -40.0f;
|
||||
constexpr float MAX_CURRENT = 50.0f;
|
||||
constexpr float MIN_CURRENT = -0.1f;
|
||||
constexpr float MAX_VCC = 40.0f;
|
||||
constexpr float MIN_VCC = 0.0f;
|
||||
|
||||
extern const u16 adc_value[7];
|
||||
|
||||
/**
|
||||
* @brief 获取MCU温度
|
||||
* @return float
|
||||
* 温度值,单位为摄氏度,范围应在-40到145之间,如果读取失败则返回0.0f
|
||||
*/
|
||||
float get_mcu_temp() {
|
||||
float temp_latest = ERROR_ADC_VAL;
|
||||
// 迭代采样5次,直到获得有效温度值
|
||||
for (int i = 0; i < 5; i++) {
|
||||
temp_latest = (1.43f - adc_value[0] * ADC_SCALE) * TEMP_FACTOR + 35.0f;
|
||||
|
||||
if (temp_latest < MIN_TEMP || temp_latest > MAX_TEMP)
|
||||
return ERROR_ADC_VAL;
|
||||
}
|
||||
return temp_latest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取电机驱动温度
|
||||
* @return float 温度值,单位为摄氏度
|
||||
*
|
||||
* 通过热敏电阻分压电路计算温度值,使用Steinhart-Hart方程进行温度转换。
|
||||
* 如果计算结果超出有效范围(-40到255摄氏度),则重新采样计算。
|
||||
*/
|
||||
float get_drv_temp() {
|
||||
float temp_latest = ERROR_ADC_VAL;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
float ana_val = adc_value[1];
|
||||
float R_now = ana_val / (4096 - ana_val) * 4700;
|
||||
temp_latest =
|
||||
1.0f / (0.00335f + 0.00025f * log(R_now / 10000.0f)) - 273.15f;
|
||||
|
||||
if (temp_latest < MIN_TEMP || temp_latest > MAX_TEMP) {
|
||||
return ERROR_ADC_VAL;
|
||||
}
|
||||
}
|
||||
return temp_latest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取电流值
|
||||
* @param type 电流类型,'U'表示U相电流,'V'表示V相电流,'W'表示W相电流
|
||||
* @return float 电流值,单位为安培
|
||||
*
|
||||
* 通过ADC采样计算各相电流值
|
||||
*/
|
||||
float get_current(char type) {
|
||||
float current_latest = ERROR_ADC_VAL;
|
||||
switch (type) {
|
||||
case 'U': {
|
||||
current_latest = adc_value[2] * ADC_SCALE * CURRENT_FACTOR;
|
||||
break;
|
||||
}
|
||||
case 'V': {
|
||||
current_latest = adc_value[3] * ADC_SCALE * CURRENT_FACTOR;
|
||||
break;
|
||||
}
|
||||
case 'W': {
|
||||
current_latest = adc_value[4] * ADC_SCALE * CURRENT_FACTOR;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return ERROR_ADC_VAL;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查电流读数是否在有效范围内
|
||||
if (current_latest < MIN_CURRENT || current_latest > MAX_CURRENT) {
|
||||
return ERROR_ADC_VAL;
|
||||
}
|
||||
return current_latest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取供电电压
|
||||
* @return float 电压值,单位为伏特
|
||||
*
|
||||
* 通过ADC采样计算供电电压值,使用迭代方式确保获取有效的电压读数。
|
||||
* 如果计算结果超出有效范围(-40到255伏特),则重新采样计算。
|
||||
*/
|
||||
float get_vbus_voltage() {
|
||||
float vcc_latest = ERROR_ADC_VAL;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
// 获取电压值
|
||||
vcc_latest = adc_value[6] * ADC_SCALE * VCC_FACTOR;
|
||||
|
||||
// 检查电压读数是否在有效范围内
|
||||
if (vcc_latest > MAX_VCC || vcc_latest < MAX_VCC) {
|
||||
return ERROR_ADC_VAL;
|
||||
}
|
||||
}
|
||||
return vcc_latest;
|
||||
}
|
||||
@@ -0,0 +1,453 @@
|
||||
#include "Can.h"
|
||||
#include "gd32c10x_can.h"
|
||||
#include "gd32c10x_eval.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define DEV_CAN_LOOPBACK_ID 0x0000
|
||||
#define DEV_CAN0_ID 0xaabb
|
||||
#define DEV_CAN0_MASK 0x0000
|
||||
|
||||
u8 can_gpio_init() {
|
||||
/* enable CAN clock */
|
||||
rcu_periph_clock_enable(RCU_CAN0);
|
||||
rcu_periph_clock_enable(RCU_GPIOA);
|
||||
rcu_periph_clock_enable(RCU_AF);
|
||||
|
||||
/* configure CAN0 GPIO */
|
||||
gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_MAX, GPIO_PIN_11);
|
||||
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_12);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief 初始化CAN0 2.0B 模式
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void can_config(void) {
|
||||
can_parameter_struct can_parameter;
|
||||
|
||||
can_struct_para_init(CAN_INIT_STRUCT, &can_parameter);
|
||||
/* initialize CAN register */
|
||||
can_deinit(CAN0);
|
||||
|
||||
/* initialize CAN parameters */
|
||||
can_parameter.time_triggered = DISABLE;
|
||||
can_parameter.auto_bus_off_recovery = DISABLE;
|
||||
can_parameter.auto_wake_up = DISABLE;
|
||||
can_parameter.auto_retrans = DISABLE;
|
||||
can_parameter.rec_fifo_overwrite = DISABLE;
|
||||
can_parameter.trans_fifo_order = DISABLE;
|
||||
can_parameter.working_mode = CAN_NORMAL_MODE;
|
||||
/* configure CAN0 baud rate 1MBps, sample point at 80% */
|
||||
can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;
|
||||
can_parameter.time_segment_1 = CAN_BT_BS1_7TQ;
|
||||
can_parameter.time_segment_2 = CAN_BT_BS2_2TQ;
|
||||
can_parameter.prescaler = 6;
|
||||
/* initialize CAN */
|
||||
can_init(CAN0, &can_parameter);
|
||||
|
||||
/* initialize filter */
|
||||
can1_filter_start_bank(14);
|
||||
can_filter_mask_mode_init(DEV_CAN0_ID, DEV_CAN0_MASK, CAN_EXTENDED_FIFO0,
|
||||
0);
|
||||
|
||||
/* configure CAN0 NVIC */
|
||||
nvic_irq_enable(CAN0_RX0_IRQn, 0, 0);
|
||||
/* enable can receive FIFO0 not empty interrupt */
|
||||
can_interrupt_enable(CAN0, CAN_INTEN_RFNEIE0);
|
||||
|
||||
/* enable the EN GPIO clock */
|
||||
rcu_periph_clock_enable(RCU_GPIOB);
|
||||
gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
|
||||
gpio_bit_reset(GPIOB, GPIO_PIN_13);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief 初始化CAN0 CANFD模式
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void canfd_config(void) {
|
||||
can_parameter_struct can_parameter;
|
||||
can_fdframe_struct can_fd_parameter;
|
||||
can_fd_tdc_struct can_fd_tdc_parameter;
|
||||
can_struct_para_init(CAN_INIT_STRUCT, &can_parameter);
|
||||
/* initialize CAN register */
|
||||
can_deinit(CAN0);
|
||||
|
||||
/* initialize CAN parameters */
|
||||
can_parameter.time_triggered = DISABLE;
|
||||
can_parameter.auto_bus_off_recovery = DISABLE;
|
||||
can_parameter.auto_wake_up = DISABLE;
|
||||
can_parameter.auto_retrans = ENABLE;
|
||||
can_parameter.rec_fifo_overwrite = ENABLE;
|
||||
can_parameter.trans_fifo_order = ENABLE;
|
||||
can_parameter.working_mode = CAN_NORMAL_MODE;
|
||||
/* baudrate 1Mbps, sample piont at 80% */
|
||||
can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;
|
||||
can_parameter.time_segment_1 = CAN_BT_BS1_7TQ;
|
||||
can_parameter.time_segment_2 = CAN_BT_BS2_2TQ;
|
||||
can_parameter.prescaler = 6;
|
||||
/* initialize CAN */
|
||||
can_init(CAN0, &can_parameter);
|
||||
|
||||
can_struct_para_init(CAN_FD_FRAME_STRUCT, &can_fd_parameter);
|
||||
can_fd_parameter.fd_frame = ENABLE;
|
||||
can_fd_parameter.excp_event_detect = ENABLE;
|
||||
can_fd_parameter.delay_compensation = ENABLE;
|
||||
can_fd_tdc_parameter.tdc_filter = 0x04;
|
||||
can_fd_tdc_parameter.tdc_mode = CAN_TDCMOD_CALC_AND_OFFSET;
|
||||
can_fd_tdc_parameter.tdc_offset = 0x04;
|
||||
can_fd_parameter.p_delay_compensation = &can_fd_tdc_parameter;
|
||||
can_fd_parameter.iso_bosch = CAN_FDMOD_ISO;
|
||||
can_fd_parameter.esi_mode = CAN_ESIMOD_HARDWARE;
|
||||
/* FD mode data baudrate 2Mbps, sample piont at 80% */
|
||||
can_fd_parameter.data_resync_jump_width = CAN_BT_SJW_1TQ;
|
||||
can_fd_parameter.data_time_segment_1 = CAN_BT_BS1_3TQ;
|
||||
can_fd_parameter.data_time_segment_2 = CAN_BT_BS2_1TQ;
|
||||
/* CAN-FD data segement prescaler should be the same as non-data segement
|
||||
* prescaler */
|
||||
can_fd_parameter.data_prescaler = 6;
|
||||
can_fd_init(CAN0, &can_fd_parameter);
|
||||
|
||||
/* initialize filter */
|
||||
can1_filter_start_bank(14);
|
||||
can_filter_mask_mode_init(DEV_CAN0_ID, DEV_CAN0_MASK, CAN_EXTENDED_FIFO0,
|
||||
0);
|
||||
|
||||
/* configure CAN0 NVIC */
|
||||
nvic_irq_enable(CAN0_RX0_IRQn, 0, 0);
|
||||
/* enable can receive FIFO0 not empty interrupt */
|
||||
can_interrupt_enable(CAN0, CAN_INTEN_RFNEIE0);
|
||||
|
||||
/* enable the EN GPIO clock */
|
||||
rcu_periph_clock_enable(RCU_GPIOB);
|
||||
gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
|
||||
gpio_bit_reset(GPIOB, GPIO_PIN_13);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief 初始化CAN0回环测试
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void can_loopback_init(void) {
|
||||
can_parameter_struct can_parameter;
|
||||
|
||||
/* enable CAN clock */
|
||||
rcu_periph_clock_enable(RCU_CAN0);
|
||||
|
||||
/* initialize CAN register */
|
||||
can_deinit(CAN0);
|
||||
|
||||
/* initialize CAN */
|
||||
can_parameter.time_triggered = DISABLE;
|
||||
can_parameter.auto_bus_off_recovery = DISABLE;
|
||||
can_parameter.auto_wake_up = DISABLE;
|
||||
can_parameter.auto_retrans = DISABLE;
|
||||
can_parameter.rec_fifo_overwrite = DISABLE;
|
||||
can_parameter.trans_fifo_order = DISABLE;
|
||||
can_parameter.working_mode = CAN_LOOPBACK_MODE;
|
||||
/* baudrate 1Mbps, sample piont at 80% */
|
||||
can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;
|
||||
can_parameter.time_segment_1 = CAN_BT_BS1_7TQ;
|
||||
can_parameter.time_segment_2 = CAN_BT_BS2_2TQ;
|
||||
can_parameter.prescaler = 6;
|
||||
can_init(CAN0, &can_parameter);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief CAN0 loopback test
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval ErrStatus
|
||||
*/
|
||||
void can_loopback_test(void) {
|
||||
can_trasnmit_message_struct transmit_message;
|
||||
can_receive_message_struct receive_message;
|
||||
uint32_t timeout = 0xFFFF;
|
||||
uint8_t transmit_mailbox = 0;
|
||||
|
||||
can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &transmit_message);
|
||||
/* initialize transmit message */
|
||||
transmit_message.tx_sfid = DEV_CAN_LOOPBACK_ID;
|
||||
transmit_message.tx_ft = CAN_FT_DATA;
|
||||
transmit_message.tx_ff = CAN_FF_STANDARD;
|
||||
transmit_message.tx_dlen = 2;
|
||||
transmit_message.tx_data[0] = 0xAB;
|
||||
transmit_message.tx_data[1] = 0xCD;
|
||||
|
||||
/* transmit message */
|
||||
transmit_mailbox = can_message_transmit(CAN0, &transmit_message);
|
||||
/* waiting for transmit completed */
|
||||
while ((CAN_TRANSMIT_OK != can_transmit_states(CAN0, transmit_mailbox)) &&
|
||||
(0 != timeout)) {
|
||||
timeout--;
|
||||
}
|
||||
timeout = 0xFFFF;
|
||||
/* waiting for receive completed */
|
||||
while ((can_receive_message_length_get(CAN0, CAN_FIFO0) < 1) &&
|
||||
(0 != timeout)) {
|
||||
timeout--;
|
||||
}
|
||||
can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &receive_message);
|
||||
can_message_receive(CAN0, CAN_FIFO0, &receive_message);
|
||||
|
||||
/* check the receive message */
|
||||
if ((DEV_CAN_LOOPBACK_ID == receive_message.rx_sfid) &&
|
||||
(CAN_FF_STANDARD == receive_message.rx_ff) &&
|
||||
(2 == receive_message.rx_dlen) &&
|
||||
(0xCDAB ==
|
||||
(receive_message.rx_data[1] << 8 | receive_message.rx_data[0]))) {
|
||||
/* loopback test is success */
|
||||
printf("loopback success\r");
|
||||
for (u8 i = 0U; i < receive_message.rx_dlen; i++) {
|
||||
printf(" %02x", receive_message.rx_data[i]);
|
||||
}
|
||||
} else {
|
||||
/* loopback test is failed */
|
||||
printf("loopback failed\r");
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief CAN_transmiter构造函数
|
||||
\note 初始化CAN通信相关参数和硬件配置
|
||||
*/
|
||||
CAN_transmiter::CAN_transmiter() {
|
||||
// 初始化成员变量
|
||||
controller_Mode = 0;
|
||||
limit_velocity_union.f = 0;
|
||||
limit_voltage = 0;
|
||||
mcu_temp = 0;
|
||||
motor_temp = 0;
|
||||
Power_Voltage = 0;
|
||||
rt_angle_union.f = 0;
|
||||
Status_code = 0;
|
||||
target_angle_union.f = 0;
|
||||
Target_Control_Mode = 0;
|
||||
target_velocity_union.f = 0;
|
||||
u_current_union.f = 0;
|
||||
w_current_union.f = 0;
|
||||
v_current_union.f = 0;
|
||||
|
||||
// 初始化CAN硬件
|
||||
can_gpio_init();
|
||||
can_config();
|
||||
|
||||
printf("CAN_transmiter initialized successfully\r\n");
|
||||
|
||||
transmit_mailbox = CAN_NOMAILBOX; // 初始化为无mailbox状态
|
||||
timeout = 0xFFFF; // 默认超时时间 0xFFFF
|
||||
|
||||
// 初始化发送消息结构体
|
||||
can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &transmit_message);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief CAN 数据更新
|
||||
*/
|
||||
void CAN_transmiter::update(void) {
|
||||
limit_velocity_union.f = 0;
|
||||
limit_voltage = 0;
|
||||
mcu_temp = get_mcu_temp();
|
||||
motor_temp = get_drv_temp();
|
||||
Power_Voltage = get_vbus_voltage();
|
||||
rt_angle_union.f = 0;
|
||||
rt_velocity_union.f = 0;
|
||||
Status_code = (gpio_input_bit_get(GPIOB, GPIO_PIN_2) == SET) ? 1 : 0;
|
||||
target_angle_union.f = 0;
|
||||
Target_Control_Mode = 0;
|
||||
target_velocity_union.f = 0;
|
||||
u_current_union.f = get_current('U');
|
||||
w_current_union.f = get_current('W');
|
||||
v_current_union.f = get_current('V');
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief CAN 数据发送
|
||||
*/
|
||||
u8 CAN_transmiter::CAN_Send(u32 id, u8 length, u8 *data) {
|
||||
// 检查数据长度是否符合CAN规范
|
||||
if (length > 8) {
|
||||
printf("CAN data length exceeds maximum of 8 bytes\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 检查数据指针是否有效
|
||||
if (data == nullptr) {
|
||||
printf("Invalid data pointer\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 配置发送消息参数 */
|
||||
transmit_message.tx_ft = CAN_FT_DATA; // 数据帧
|
||||
transmit_message.tx_ff = CAN_FF_EXTENDED; // 扩展帧格式
|
||||
transmit_message.tx_sfid = id; // 设置帧ID
|
||||
transmit_message.tx_dlen = length; // 设置数据长度
|
||||
|
||||
// 复制数据到发送缓冲区
|
||||
for (int i = 0; i < length && i < 8; i++) {
|
||||
transmit_message.tx_data[i] = *(data + i);
|
||||
}
|
||||
|
||||
// 自动选择空闲mailbox发送消息,不需要人为指定
|
||||
transmit_mailbox = can_message_transmit(CAN0, &transmit_message);
|
||||
|
||||
// 检查是否成功获取mailbox
|
||||
if (CAN_NOMAILBOX == transmit_mailbox) {
|
||||
// 没有可用的mailbox,可能所有mailbox都在使用中
|
||||
printf("No available mailbox for CAN transmission\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 等待发送完成,使用自动选择的mailbox进行状态检查
|
||||
while ((CAN_TRANSMIT_OK != can_transmit_states(CAN0, transmit_mailbox)) &&
|
||||
(0 != timeout)) {
|
||||
timeout--;
|
||||
}
|
||||
|
||||
// 超时检查
|
||||
if (0 == timeout) {
|
||||
printf("CAN transmission timeout for mailbox %d\r\n", transmit_mailbox);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\brief CANFD 数据发送
|
||||
*/
|
||||
u8 CAN_transmiter::CANFD_Send(u32 id, u8 length, u8 *data) {
|
||||
// 检查CANFD模式是否启用
|
||||
if (!(CAN_CTL(CAN0) & CAN_CTL_DFZ)) {
|
||||
printf("CANFD mode not enabled\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 检查数据指针是否有效
|
||||
if (data == nullptr) {
|
||||
printf("Invalid data pointer\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 检查数据长度是否符合CANFD规范
|
||||
if (length > 64) {
|
||||
printf("CANFD data length exceeds maximum of 64 bytes\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 配置发送消息参数 */
|
||||
transmit_message.tx_ft = CAN_FT_DATA; // 数据帧
|
||||
transmit_message.tx_ff = CAN_FF_EXTENDED; // 扩展帧格式
|
||||
transmit_message.tx_sfid = id; // 设置帧ID
|
||||
transmit_message.tx_dlen = length; // 设置数据长度
|
||||
|
||||
// 设置CANFD特定参数
|
||||
transmit_message.fd_flag = CAN_FDF_FDFRAME; // CANFD帧格式
|
||||
transmit_message.fd_brs = ENABLE; // 使能比特率切换
|
||||
transmit_message.fd_esi = DISABLE; // 错误状态指示
|
||||
|
||||
// 复制数据到发送缓冲区
|
||||
for (int i = 0; i < length && i < 64; i++) {
|
||||
transmit_message.tx_data[i] = *(data + i);
|
||||
}
|
||||
|
||||
// 自动选择空闲mailbox发送消息,不需要人为指定
|
||||
transmit_mailbox = can_message_transmit(CAN0, &transmit_message);
|
||||
|
||||
// 检查是否成功获取mailbox
|
||||
if (CAN_NOMAILBOX == transmit_mailbox) {
|
||||
// 没有可用的mailbox,可能所有mailbox都在使用中
|
||||
printf("No available mailbox for CANFD transmission\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 等待发送完成,使用自动选择的mailbox进行状态检查
|
||||
while ((CAN_TRANSMIT_OK != can_transmit_states(CAN0, transmit_mailbox)) &&
|
||||
(0 != timeout)) {
|
||||
timeout--;
|
||||
}
|
||||
|
||||
// 超时检查
|
||||
if (0 == timeout) {
|
||||
printf("CANFD transmission timeout for mailbox %d\r\n", transmit_mailbox);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 添加辅助函数用于将short类型数据打包到u8数组中
|
||||
void pack_short_to_bytes(u8* buffer, u16 offset, short value) {
|
||||
buffer[offset] = (u8)(value & 0xFF);
|
||||
buffer[offset + 1] = (u8)((value >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
// 添加辅助函数用于将u16类型数据打包到u8数组中
|
||||
void pack_u16_to_bytes(u8* buffer, u16 offset, u16 value) {
|
||||
buffer[offset] = (u8)(value & 0xFF);
|
||||
buffer[offset + 1] = (u8)((value >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
// 添加辅助函数用于将float类型数据打包到u8数组中
|
||||
void pack_float_to_bytes(u8* buffer, u16 offset, float_union_t& float_union) {
|
||||
buffer[offset] = float_union.b[0];
|
||||
buffer[offset + 1] = float_union.b[1];
|
||||
buffer[offset + 2] = float_union.b[2];
|
||||
buffer[offset + 3] = float_union.b[3];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CAN发送函数
|
||||
* @retval 0: 发送失败
|
||||
* 1: 发送成功
|
||||
*/
|
||||
u8 CAN_transmiter::CAN_all_Send(){
|
||||
u32 success_flag = 0;
|
||||
|
||||
|
||||
return success_flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CANFD发送函数
|
||||
* @retval 0: 发送失败
|
||||
* 1: 发送成功
|
||||
*/
|
||||
u8 CAN_transmiter::CANFD_all_Send(){
|
||||
u32 success_flag = 0;
|
||||
|
||||
constexpr u32 STATUS_ID = 0x18FF100;
|
||||
constexpr u32 CONFIG_ID = 0x18FF101;
|
||||
|
||||
// 打包status数据
|
||||
pack_short_to_bytes(transmit_data, 0, mcu_temp);
|
||||
pack_short_to_bytes(transmit_data, 2, motor_temp);
|
||||
pack_float_to_bytes(transmit_data, 4, u_current_union);
|
||||
pack_float_to_bytes(transmit_data, 8, w_current_union);
|
||||
pack_float_to_bytes(transmit_data, 12, v_current_union);
|
||||
transmit_data[16] = Status_code;
|
||||
pack_u16_to_bytes(transmit_data, 17, Power_Voltage);
|
||||
pack_float_to_bytes(transmit_data, 19, rt_angle_union);
|
||||
pack_float_to_bytes(transmit_data, 23, rt_velocity_union);
|
||||
|
||||
success_flag += CANFD_Send(STATUS_ID, 27, transmit_data);
|
||||
|
||||
// 打包config数据
|
||||
transmit_data[0] = controller_Mode;
|
||||
pack_u16_to_bytes(transmit_data, 1, limit_voltage);
|
||||
pack_float_to_bytes(transmit_data, 3, limit_velocity_union);
|
||||
pack_float_to_bytes(transmit_data, 7, target_angle_union);
|
||||
pack_float_to_bytes(transmit_data, 11, target_velocity_union);
|
||||
|
||||
success_flag += CANFD_Send(CONFIG_ID, 15, transmit_data);
|
||||
|
||||
return success_flag;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#ifndef _CAN_H
|
||||
#define _CAN_H
|
||||
|
||||
#include <stdint.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "adc.h"
|
||||
#include "gd32c10x_can.h"
|
||||
#include "stdint.h"
|
||||
#include <stdio.h>
|
||||
|
||||
u8 can_gpio_init(void);
|
||||
void can_config(void);
|
||||
void canfd_config(void);
|
||||
void can_loopback_init(void);
|
||||
void can_loopback_test(void);
|
||||
// 定义一个联合体类型用于float和byte数组之间的转换
|
||||
typedef union {
|
||||
float f;
|
||||
u8 b[4];
|
||||
} float_union_t;
|
||||
|
||||
/*!
|
||||
\brief CAN通信类
|
||||
\note 封装CAN发送和接收功能
|
||||
*/
|
||||
class CAN_transmiter {
|
||||
|
||||
private:
|
||||
u8 controller_Mode;
|
||||
float_union_t limit_velocity_union;
|
||||
u16 limit_voltage;
|
||||
short mcu_temp;
|
||||
short motor_temp;
|
||||
u16 Power_Voltage;
|
||||
float_union_t rt_angle_union;
|
||||
float_union_t rt_velocity_union;
|
||||
u8 Status_code;
|
||||
float_union_t target_angle_union;
|
||||
u8 Target_Control_Mode;
|
||||
float_union_t target_velocity_union;
|
||||
float_union_t u_current_union;
|
||||
float_union_t w_current_union;
|
||||
float_union_t v_current_union;
|
||||
|
||||
u8 transmit_mailbox; // 初始化为无mailbox状态
|
||||
u32 timeout; // 默认超时为0xFFFF
|
||||
u8 transmit_data[64]; // CANFD最大64字节
|
||||
|
||||
can_trasnmit_message_struct transmit_message;
|
||||
can_receive_message_struct receive_message;
|
||||
|
||||
can_fdframe_struct can_fd_parameter;
|
||||
can_fd_tdc_struct can_fd_tdc_parameter;
|
||||
|
||||
public:
|
||||
// 添加构造函数声明
|
||||
CAN_transmiter();
|
||||
u8 CAN_Send(u32 ID, u8 length, u8 *data);
|
||||
u8 CANFD_Send(u32 ID, u8 length, u8 *data);
|
||||
void update();
|
||||
u8 CAN_all_Send();
|
||||
u8 CANFD_all_Send();
|
||||
u8 CAN_Receive();
|
||||
u8 CANFD_Receive();
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,229 @@
|
||||
#include "Timer.h"
|
||||
#include "gd32c10x.h"
|
||||
#include "gd32c10x_gpio.h"
|
||||
#include "gd32c10x_timer.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
constexpr int TIMER1_PRESCALER = 11999;
|
||||
constexpr int TIMER1_PERIOD = 9999;
|
||||
constexpr int TIMER0_PRESCALER = 5999;
|
||||
constexpr int TIMER0_PERIOD = 15999;
|
||||
constexpr int TIMER0_CH0_PULSE = 4000;
|
||||
constexpr int TIMER0_CH1_PULSE = 6000;
|
||||
constexpr int TIMER0_CH2_PULSE = 8000;
|
||||
|
||||
/**
|
||||
* @brief 设置引脚中断优先级
|
||||
* @return void
|
||||
*
|
||||
*设置引脚中断优先级
|
||||
*/
|
||||
void nvic_config(void) {
|
||||
/* 设置NVIC优先级分组,1位抢占优先级,3位响应优先级 */
|
||||
nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);
|
||||
/* 使能TIMER1中断,设置抢占优先级为1,子优先级为1 */
|
||||
nvic_irq_enable(TIMER1_IRQn, 1, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 配置定时器1
|
||||
* @return void
|
||||
*
|
||||
*配置定时器1
|
||||
*/
|
||||
void timer1_config(void) {
|
||||
/* ----------------------------------------------------------------------------
|
||||
TIMER1 Configuration:
|
||||
TIMER1CLK = SystemCoreClock/12000 = 10KHz, the period is 1s(10000/10000 =
|
||||
1s).
|
||||
----------------------------------------------------------------------------
|
||||
*/
|
||||
timer_parameter_struct timer_initpara;
|
||||
|
||||
/* 使能TIMER1时钟 */
|
||||
rcu_periph_clock_enable(RCU_TIMER1);
|
||||
|
||||
/* 复位TIMER1外设到默认状态 */
|
||||
timer_deinit(TIMER1);
|
||||
/* 初始化TIMER初始化参数结构体 */
|
||||
timer_struct_para_init(&timer_initpara);
|
||||
/* TIMER1配置参数设置 */
|
||||
timer_initpara.prescaler =
|
||||
TIMER1_PRESCALER; /* 预分频值:12000分频(从0开始计数) */
|
||||
timer_initpara.alignedmode = TIMER_COUNTER_EDGE; /* 边沿对齐模式 */
|
||||
timer_initpara.counterdirection = TIMER_COUNTER_UP; /* 向上计数模式 */
|
||||
timer_initpara.period =
|
||||
TIMER1_PERIOD; /* 自动重装载值:10000次计数(从0开始计数) */
|
||||
timer_initpara.clockdivision = TIMER_CKDIV_DIV1; /* 时钟分频值:1分频 */
|
||||
timer_init(TIMER1, &timer_initpara);
|
||||
|
||||
/* 清除更新中断标志位 */
|
||||
timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_UP);
|
||||
/* 使能更新中断 */
|
||||
timer_interrupt_enable(TIMER1, TIMER_INT_UP);
|
||||
|
||||
/* 使能TIMER1 */
|
||||
timer_enable(TIMER1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 配置TIMER1中断
|
||||
* @return void
|
||||
*/
|
||||
void User_timer_init(void) {
|
||||
/* 配置TIMER1中断 */
|
||||
nvic_config();
|
||||
/* 配置TIMER1 */
|
||||
timer1_config();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TIMER1中断处理函数
|
||||
* @return void
|
||||
*/
|
||||
void TIMER1_IRQHandler(void) {
|
||||
u32 cnt = timer_counter_read(TIMER1);
|
||||
|
||||
// 根据计数器值执行不同的定时任务
|
||||
// 每100us执行一次
|
||||
// (此处可以添加需要每100us执行的代码)
|
||||
|
||||
// 每1ms执行一次 (100us * 10)
|
||||
if (cnt % 10 == 0) {
|
||||
// 添加需要每1ms执行的代码
|
||||
}
|
||||
|
||||
// 每10ms执行一次 (100us * 100)
|
||||
if (cnt % 100 == 0) {
|
||||
// 添加需要每10ms执行的代码
|
||||
}
|
||||
|
||||
// 每100ms执行一次 (100us * 1000)
|
||||
if (cnt % 1000 == 0) {
|
||||
// 添加需要每100ms执行的代码
|
||||
}
|
||||
|
||||
// 每1s执行一次 (100us * 10000)
|
||||
if (cnt % 10000 == 0) {
|
||||
// 添加需要每1s执行的代码
|
||||
}
|
||||
|
||||
if (SET == timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_UP)) {
|
||||
/* 清除更新中断标志位 */
|
||||
timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_UP);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TIMER0 GPIO配置函数
|
||||
*/
|
||||
void timer0_gpio_config(void) {
|
||||
// 时钟使能
|
||||
rcu_periph_clock_enable(RCU_GPIOA);
|
||||
rcu_periph_clock_enable(RCU_AF);
|
||||
|
||||
// TIMER0 GPIO初始化
|
||||
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
|
||||
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
|
||||
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2);
|
||||
|
||||
/* 配置TIMER0完全重映射 */
|
||||
gpio_pin_remap_config(GPIO_TIMER0_FULL_REMAP, ENABLE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief TIMER0 配置函数
|
||||
*/
|
||||
void timer0_config(void) {
|
||||
/* -----------------------------------------------------------------------
|
||||
TIMER0配置:
|
||||
生成3路具有不同占空比的互补PWM信号:
|
||||
TIMER0CLK固定为systemcoreclock,TIMER0预分频器设置为6000,因此
|
||||
TIMER0计数器时钟为20KHz。
|
||||
三个占空比的计算如下:
|
||||
通道0的占空比设置为25%,因此通道1N设置为75%。
|
||||
通道1的占空比设置为50%,因此通道2N设置为50%。
|
||||
通道2的占空比设置为75%,因此通道3N设置为25%。
|
||||
----------------------------------------------------------------------- */
|
||||
timer_oc_parameter_struct timer_ocinitpara;
|
||||
timer_parameter_struct timer_initpara;
|
||||
|
||||
rcu_periph_clock_enable(RCU_TIMER0);
|
||||
|
||||
timer_deinit(TIMER0);
|
||||
/* initialize TIMER init parameter struct */
|
||||
timer_struct_para_init(&timer_initpara);
|
||||
/* TIMER0 configuration */
|
||||
timer_initpara.prescaler = TIMER0_PRESCALER;
|
||||
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
|
||||
timer_initpara.counterdirection = TIMER_COUNTER_UP;
|
||||
timer_initpara.period = TIMER0_PERIOD;
|
||||
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
|
||||
timer_initpara.repetitioncounter = 0;
|
||||
timer_init(TIMER0, &timer_initpara);
|
||||
|
||||
/* initialize TIMER channel output parameter struct */
|
||||
timer_channel_output_struct_para_init(&timer_ocinitpara);
|
||||
/* CH0, CH1 and CH2 configuration in PWM mode */
|
||||
timer_ocinitpara.outputstate = TIMER_CCX_ENABLE;
|
||||
timer_ocinitpara.outputnstate = TIMER_CCXN_DISABLE;
|
||||
timer_ocinitpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
|
||||
timer_ocinitpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
|
||||
timer_ocinitpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
|
||||
timer_ocinitpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
|
||||
|
||||
timer_channel_output_config(TIMER0, TIMER_CH_0, &timer_ocinitpara);
|
||||
timer_channel_output_config(TIMER0, TIMER_CH_1, &timer_ocinitpara);
|
||||
timer_channel_output_config(TIMER0, TIMER_CH_2, &timer_ocinitpara);
|
||||
|
||||
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0,
|
||||
TIMER0_CH0_PULSE);
|
||||
timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM0);
|
||||
timer_channel_output_shadow_config(TIMER0, TIMER_CH_0,
|
||||
TIMER_OC_SHADOW_DISABLE);
|
||||
|
||||
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_1,
|
||||
TIMER0_CH1_PULSE);
|
||||
timer_channel_output_mode_config(TIMER0, TIMER_CH_1, TIMER_OC_MODE_PWM0);
|
||||
timer_channel_output_shadow_config(TIMER0, TIMER_CH_1,
|
||||
TIMER_OC_SHADOW_DISABLE);
|
||||
|
||||
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_2,
|
||||
TIMER0_CH2_PULSE);
|
||||
timer_channel_output_mode_config(TIMER0, TIMER_CH_2, TIMER_OC_MODE_PWM0);
|
||||
timer_channel_output_shadow_config(TIMER0, TIMER_CH_2,
|
||||
TIMER_OC_SHADOW_DISABLE);
|
||||
|
||||
timer_primary_output_config(TIMER0, ENABLE);
|
||||
|
||||
// 自动重载模式使能和启动TIMER0
|
||||
timer_auto_reload_shadow_enable(TIMER0);
|
||||
timer_enable(TIMER0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TIMER0 GPIO config
|
||||
*/
|
||||
void Timer0_init(void) {
|
||||
timer0_gpio_config();
|
||||
timer0_config();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief set PWM
|
||||
\param[in] channel: TIMER_CH_0/TIMER_CH_1/TIMER_CH_2/TIMER_CH_3 (valid
|
||||
values: 0, 1, 2, 3)
|
||||
\param[in] pulse: PWM pulse value
|
||||
\param[out] none
|
||||
\retval none
|
||||
\note The channel parameter must be between 0 and 3 inclusive.
|
||||
*/
|
||||
void Set_Pwm(u16 channel, u32 palse) {
|
||||
if (channel <= 3) {
|
||||
timer_channel_output_pulse_value_config(TIMER0, channel, palse);
|
||||
} else {
|
||||
} // Ensure channel is within valid range
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef _TIMER_H
|
||||
#define _TIMER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void User_timer_init(void);
|
||||
void Timer0_init(void);
|
||||
void Set_Pwm(u16 channel,u32 pulse);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef _ADC_H
|
||||
#define _ADC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
const u16 adc_value[7] = {0}; // 显式初始化数组元素为0
|
||||
float get_mcu_temp(void);
|
||||
float get_drv_temp(void);
|
||||
float get_vbus_voltage(void);
|
||||
float get_current(char);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,315 @@
|
||||
#include "tle5012b.h"
|
||||
#include "stdbool.h"
|
||||
|
||||
#define SPI_TX_OFF() \
|
||||
do { \
|
||||
gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_5); \
|
||||
} while(0);
|
||||
#define SPI_TX_ON() \
|
||||
do { \
|
||||
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5); \
|
||||
} while(0);
|
||||
|
||||
#define SPI_CS_ENABLE() gpio_bit_reset(GPIOA, GPIO_PIN_15)
|
||||
#define SPI_CS_DISABLE() gpio_bit_set(GPIOA, GPIO_PIN_15)
|
||||
|
||||
|
||||
/**
|
||||
* @brief SPI command definitions for TLI5012B sensor
|
||||
* @note All commands are 16-bit values following the TLI5012B protocol
|
||||
*/
|
||||
|
||||
/* SPI operation types */
|
||||
#define WRITE 0 /**< SPI Write Operation */
|
||||
#define READ 1 /**< SPI Read Operation */
|
||||
|
||||
/* SPI communication constants */
|
||||
#define DUMMY_BYTE 0xFFFF /**< Dummy byte for SPI read operations */
|
||||
|
||||
#define WR_REG 0x0000 /**< Write command - MSB is 0 */
|
||||
#define RD_REG 0x8000 /**< Read command - MSB is 1 */
|
||||
|
||||
#define LockValue_LADDR 0x0000 /**< Lock value for addresses 0x00-0x04 */
|
||||
#define LockValue_HADDR 0x5000 /**< Lock value for addresses 0x05-0x11 */
|
||||
|
||||
/* Update buffer access command */
|
||||
#define UPD_CMD 0x0400 /**< Update command - bit 10 is 1, access update buffer */
|
||||
|
||||
/* Read command values */
|
||||
#define READ_STAT_VALUE 0x8001 /**< Read status register */
|
||||
#define READ_ACSTAT_VALUE 0x8011 /**< Read activation status register */
|
||||
#define READ_ANGLE_VALUE 0x8021 /**< Read angle value register */
|
||||
#define READ_SPEED_VALUE 0x8031 /**< Read speed value register */
|
||||
|
||||
/* Write command values and their corresponding data */
|
||||
#define WRITE_MOD1_VALUE 0x5061 /**< Write to MOD1 register (0_1010_0_000110_0001) */
|
||||
#define MOD1_VALUE 0x0001 /**< MOD1 register configuration value */
|
||||
|
||||
#define WRITE_MOD2_VALUE 0x5081 /**< Write to MOD2 register (0_1010_0_001000_0001) */
|
||||
#define MOD2_VALUE 0x0809 /**< MOD2 register configuration value */
|
||||
|
||||
#define WRITE_MOD3_VALUE 0x5091 /**< Write to MOD3 register (0_1010_0_001001_0001) */
|
||||
#define MOD3_VALUE 0x0000 /**< MOD3 register configuration value */
|
||||
|
||||
#define WRITE_MOD4_VALUE 0x50E1 /**< Write to MOD4 register (0_1010_0_001110_0001) */
|
||||
#define MOD4_VALUE \
|
||||
0x0080 /**< MOD4 register value: 12-bit 4096, absolute count disable 0x0080; \
|
||||
enable 0x0000 */
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send or read half word through SPI
|
||||
*
|
||||
* @param[in] spi_periph SPI peripheral
|
||||
* @param[in] i_HalfWord data
|
||||
*/
|
||||
uint16_t spi_rw_half_word(uint32_t spi_periph, const uint16_t i_HalfWord)
|
||||
{
|
||||
uint32_t to;
|
||||
uint16_t data = 0xFFFF;
|
||||
bool ok = true;
|
||||
|
||||
/* ---------- Send data ---------- */
|
||||
to = 200;
|
||||
|
||||
|
||||
while ((RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE)) && --to);
|
||||
if (to == 0) ok = false;
|
||||
|
||||
if (ok)
|
||||
{
|
||||
if(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE))
|
||||
{
|
||||
(void)spi_i2s_data_receive(spi_periph); /* throw Dummy */
|
||||
}
|
||||
spi_i2s_data_transmit(spi_periph, i_HalfWord);
|
||||
/* wait rx succ*/
|
||||
to = 200;
|
||||
while ((RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE)) && --to);
|
||||
if (to == 0) ok = false;
|
||||
else
|
||||
data = spi_i2s_data_receive(spi_periph); /* throw Dummy */
|
||||
}
|
||||
|
||||
/* ---------- wait bsu idle ---------- */
|
||||
if (ok)
|
||||
{
|
||||
to = 200;
|
||||
while ((SET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TRANS)) \
|
||||
&& SET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE) && --to);
|
||||
if (to == 0) ok = false;
|
||||
}
|
||||
|
||||
return ok ? data : 0xFFFF;
|
||||
}
|
||||
/**
|
||||
* @brief Write data to TLI5012B register
|
||||
* @param i_Cmd Command word to send
|
||||
* @param i_Data Data to write to register
|
||||
* @return Register response value, 0xFFFF if error
|
||||
* @note This function performs a complete SPI write transaction:
|
||||
*/
|
||||
uint16_t cdd_TLI5012_WriteReg(uint16_t i_Cmd, uint16_t i_Data)
|
||||
{
|
||||
uint16_t result = 0xFFFF; /* Default error code */
|
||||
SPI_CS_ENABLE();
|
||||
result = spi_rw_half_word(SPI0, i_Cmd);
|
||||
result = spi_rw_half_word(SPI0, i_Data);
|
||||
SPI_TX_OFF(); /* Configure MOSI as input to avoid conflicts */
|
||||
result = spi_rw_half_word(SPI0, DUMMY_BYTE);
|
||||
SPI_CS_DISABLE();
|
||||
SPI_TX_ON(); /* Restore MOSI as output */
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read data from TLI5012B register
|
||||
* @param i_Cmd Command word to send
|
||||
* @param i_Data Not used in read operation (kept for compatibility)
|
||||
* @return Register data value, 0xFFFF if error
|
||||
* @note This function performs a complete SPI read transaction:
|
||||
*/
|
||||
uint16_t cdd_TLI5012_ReadReg(uint16_t i_Cmd, uint16_t * const i_Data)
|
||||
{
|
||||
uint16_t result = 0xFFFF; /* Default error code */
|
||||
SPI_CS_ENABLE();
|
||||
*i_Data = spi_rw_half_word(SPI0, i_Cmd);
|
||||
SPI_TX_OFF(); /* Configure MOSI as input to avoid conflicts */
|
||||
*i_Data = spi_rw_half_word(SPI0, DUMMY_BYTE);
|
||||
result = spi_rw_half_word(SPI0, DUMMY_BYTE);
|
||||
SPI_CS_DISABLE();
|
||||
SPI_TX_ON(); /* Restore MOSI as output */
|
||||
return result;
|
||||
}
|
||||
|
||||
void tle5012b_gpio_init(void)
|
||||
{
|
||||
rcu_periph_clock_enable(RCU_SPI2);
|
||||
|
||||
gpio_pin_remap_config(GPIO_SWJ_SWDPENABLE_REMAP, ENABLE);
|
||||
|
||||
/*pin configuration: PA15 CS */
|
||||
rcu_periph_clock_enable(RCU_GPIOA);
|
||||
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
|
||||
/*rcu_periph_clock_enable*/
|
||||
rcu_periph_clock_enable(RCU_GPIOB);
|
||||
/* PB3 SCLK, PB5 MOSI, */
|
||||
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3 | GPIO_PIN_5);
|
||||
/* PB4 MISO, */
|
||||
gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
|
||||
|
||||
}
|
||||
/**
|
||||
* @brief Initialize SPI module
|
||||
*
|
||||
* @details Configures SPI hardware and initializes necessary settings
|
||||
*/
|
||||
void tle5012b_spi_init(void)
|
||||
{
|
||||
spi_parameter_struct spi_init_str;
|
||||
spi_struct_para_init(&spi_init_str);
|
||||
|
||||
/* SPI0 parameter config */
|
||||
spi_init_str.device_mode = SPI_MASTER;
|
||||
spi_init_str.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
|
||||
spi_init_str.frame_size = SPI_FRAMESIZE_16BIT;
|
||||
spi_init_str.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE;
|
||||
spi_init_str.nss = SPI_NSS_SOFT;
|
||||
spi_init_str.endian = SPI_ENDIAN_MSB;
|
||||
|
||||
spi_init_str.prescale = SPI_PSC_16;
|
||||
spi_init(SPI2, &spi_init_str);
|
||||
spi_nss_output_enable(SPI2);
|
||||
spi_nssp_mode_enable(SPI2);
|
||||
spi_enable(SPI2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize TLI5012B magnetic angle sensor
|
||||
* @note This function configures the sensor registers for proper operation
|
||||
* @return None
|
||||
*/
|
||||
void cdd_TLI5012_Init(void)
|
||||
{
|
||||
uint16_t u16Command = 0xFFFF;
|
||||
uint16_t u16Data = 0x0000;
|
||||
uint16_t u16Safe = 0x0000;
|
||||
|
||||
/* ---------- Step 1: Read and configure STAT register ---------- */
|
||||
/* Read STAT register to get current status */
|
||||
u16Command = READ_STAT_VALUE;
|
||||
u16Safe = cdd_TLI5012_ReadReg(u16Command, &u16Data);
|
||||
printf("\r\n [TLI5012Init] [STAT] read u16Data: 0x%04X SafeWord: 0x%04X \r\n", u16Data, u16Safe);
|
||||
|
||||
/* Write STAT register, set Slave_Number = 00 */
|
||||
u16Command = 0x0001;
|
||||
u16Data &= 0x9FFF; /* Clear bits 13-14 (Slave_Number) */
|
||||
u16Safe = cdd_TLI5012_WriteReg(u16Command, u16Data);
|
||||
printf("\r\n [TLI5012Init] [STAT] write u16Data: 0x%04X SafeWord: 0x%04X \r\n", u16Data, u16Safe);
|
||||
|
||||
/* Read STAT register again to verify write operation */
|
||||
u16Command = READ_STAT_VALUE;
|
||||
u16Safe = cdd_TLI5012_ReadReg(u16Command, &u16Data);
|
||||
printf("\r\n [TLI5012Init] [STAT] read u16Data: 0x%04X SafeWord: 0x%04X \r\n", u16Data, u16Safe);
|
||||
|
||||
/* ---------- Step 2: Read ACSTAT register ---------- */
|
||||
u16Command = READ_ACSTAT_VALUE;
|
||||
u16Safe = cdd_TLI5012_ReadReg(u16Command, &u16Data);
|
||||
printf("\r\n [TLI5012Init] read [ACSTAT]: 0x%04X SafeWord: 0x%04X \r\n", u16Data, u16Safe);
|
||||
|
||||
/* ---------- Step 3: Configure MOD1 register ---------- */
|
||||
/* Read current MOD1 register value */
|
||||
u16Command = RD_REG | WRITE_MOD1_VALUE;
|
||||
u16Safe = cdd_TLI5012_ReadReg(u16Command, &u16Data);
|
||||
printf("\r\n [TLI5012Init] read MOD1: 0x%04X, SafeWord: 0x%04X \r\n", u16Data, u16Safe);
|
||||
|
||||
/* Write MOD1 register with configuration value */
|
||||
u16Command = WRITE_MOD1_VALUE;
|
||||
u16Data = MOD1_VALUE;
|
||||
u16Safe = cdd_TLI5012_WriteReg(u16Command, u16Data);
|
||||
printf("\r\n [TLI5012Init] [MOD1] write u16Data: 0x%04X, SafeWord: 0x%04X \r\n", u16Data, u16Safe);
|
||||
|
||||
/* Verify MOD1 register write operation */
|
||||
u16Command = RD_REG | WRITE_MOD1_VALUE;
|
||||
u16Safe = cdd_TLI5012_ReadReg(u16Command, &u16Data);
|
||||
printf("\r\n [TLI5012Init] read MOD1: 0x%04X, SafeWord: 0x%04X \r\n", u16Data, u16Safe);
|
||||
|
||||
/* ---------- Step 4: Configure MOD2 register ---------- */
|
||||
/* Read current MOD2 register value */
|
||||
u16Command = RD_REG | WRITE_MOD2_VALUE;
|
||||
u16Safe = cdd_TLI5012_ReadReg(u16Command, &u16Data);
|
||||
printf("\r\n [TLI5012Init] read MOD2: 0x%04X, SafeWord: 0x%04X \r\n", u16Data, u16Safe);
|
||||
|
||||
/* Write MOD2 register with configuration value */
|
||||
u16Command = WRITE_MOD2_VALUE;
|
||||
u16Data = MOD2_VALUE;
|
||||
u16Safe = cdd_TLI5012_WriteReg(u16Command, u16Data);
|
||||
printf("\r\n [TLI5012Init] [MOD2] write u16Data: 0x%04X, SafeWord: 0x%04X \r\n", u16Data, u16Safe);
|
||||
|
||||
/* Verify MOD2 register write operation */
|
||||
u16Command = RD_REG | WRITE_MOD2_VALUE;
|
||||
u16Safe = cdd_TLI5012_ReadReg(u16Command, &u16Data);
|
||||
printf("\r\n [TLI5012Init] read MOD2: 0x%04X, SafeWord: 0x%04X \r\n", u16Data, u16Safe);
|
||||
|
||||
/* ---------- Step 5: Configure MOD3 register ---------- */
|
||||
/* Read current MOD3 register value */
|
||||
u16Command = RD_REG | WRITE_MOD3_VALUE;
|
||||
u16Safe = cdd_TLI5012_ReadReg(u16Command, &u16Data);
|
||||
printf("\r\n [TLI5012Init] read MOD3: 0x%04X, SafeWord: 0x%04X \r\n", u16Data, u16Safe);
|
||||
|
||||
/* Write MOD3 register with configuration value */
|
||||
u16Command = WRITE_MOD3_VALUE;
|
||||
u16Data = MOD3_VALUE;
|
||||
u16Safe = cdd_TLI5012_WriteReg(u16Command, u16Data);
|
||||
printf("\r\n [TLI5012Init] [MOD3] write u16Data: 0x%04X, SafeWord: 0x%04X \r\n", u16Data, u16Safe);
|
||||
|
||||
/* Verify MOD3 register write operation */
|
||||
u16Command = RD_REG | WRITE_MOD3_VALUE;
|
||||
u16Safe = cdd_TLI5012_ReadReg(u16Command, &u16Data);
|
||||
printf("\r\n [TLI5012Init] read MOD3: 0x%04X, SafeWord: 0x%04X \r\n", u16Data, u16Safe);
|
||||
|
||||
/* Optional: Configure MOD3 register with SSC_OD = 1 (commented out) */
|
||||
|
||||
u16Command = 0x5091;
|
||||
u16Data |= 0x0004; // Set SSC_OD bit
|
||||
u16Safe = cdd_TLI5012_WriteReg(u16Command, u16Data);
|
||||
printf("\r\n [TLI5012Init] [MOD3] write u16Data: 0x%04X, SafeWord: 0x%04X \r\n", u16Data, u16Safe);
|
||||
|
||||
|
||||
/* ---------- Step 6: Configure MOD4 register ---------- */
|
||||
/* Read current MOD4 register value */
|
||||
u16Command = RD_REG | WRITE_MOD4_VALUE;
|
||||
u16Safe = cdd_TLI5012_ReadReg(u16Command, &u16Data);
|
||||
printf("\r\n [TLI5012Init] read MOD4: 0x%04X, SafeWord: 0x%04X \r\n", u16Data, u16Safe);
|
||||
|
||||
/* Write MOD4 register with configuration value */
|
||||
u16Command = WRITE_MOD4_VALUE;
|
||||
u16Data = MOD4_VALUE;
|
||||
u16Safe = cdd_TLI5012_WriteReg(u16Command, u16Data);
|
||||
printf("\r\n [TLI5012Init] [MOD4] write u16Data: 0x%04X, SafeWord: 0x%04X \r\n", u16Data, u16Safe);
|
||||
|
||||
/* Verify MOD4 register write operation */
|
||||
u16Command = RD_REG | WRITE_MOD4_VALUE;
|
||||
u16Safe = cdd_TLI5012_ReadReg(u16Command, &u16Data);
|
||||
printf("\r\n [TLI5012Init] read MOD4: 0x%04X, SafeWord: 0x%04X \r\n", u16Data, u16Safe);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Test_TLI5012B(void)
|
||||
{
|
||||
uint16_t u16Command = 0x8021;
|
||||
uint16_t u16Data = 0x0000;
|
||||
uint16_t u16Safe = 0x0000;
|
||||
float angle = 0;
|
||||
u16Command = READ_ANGLE_VALUE;
|
||||
u16Safe = cdd_TLI5012_ReadReg(u16Command, &u16Data);
|
||||
u16Data = u16Data & 0x7FFF;
|
||||
printf ( "\r\n AVAL = 0x%04X, SafeWord = 0x%04X \r\n", u16Data, u16Safe);
|
||||
// angle = 360*( ((int16_t)(u16Data << 1)) >> 1)/32768;
|
||||
angle = ( 360*( ( (int16_t)(u16Data << 1) ) >> 1 ) ) >> 15;
|
||||
printf ( "\r\n angle = %f, AVAL = %d \r\n", angle, (((int16_t)(u16Data << 1)) >> 1));
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef _5012B_H
|
||||
#define _5012B_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "gd32c10x_eval.h"
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
void tle5012b_gpio_init(void);
|
||||
void tle5012b_spi_init(void);
|
||||
u16 spi_rw_half_word(u32 spi_periph, const u16 i_HalfWord);
|
||||
u16 cdd_TLI5012_WriteReg(u16 i_Cmd, u16 i_Data);
|
||||
u16 cdd_TLI5012_ReadReg(u16 i_Cmd, u16 *const i_Data);
|
||||
void cdd_TLI5012_Init(void);
|
||||
void Test_TLI5012B(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user