1076 lines
36 KiB
C
1076 lines
36 KiB
C
#include "main.h"
|
||
#include "user_init.h"
|
||
#include "lin.h"
|
||
#include "uart.h"
|
||
|
||
#define FRAME_DATA_MAX_LEN 11 /* 帧最大数据长度 */
|
||
#define SCHEDULE_FRAME_MAX_NUM 255 /* 进度表最大帧数量 */
|
||
|
||
#define FRAME_TYPE_UNCONDITIONAL 0 /* 无条件帧 */
|
||
#define FRAME_TYPE_EVENT_TRIGGER 1 /* 事件触发帧 */
|
||
#define FRAME_TYPE_SPORADIC 2 /* 偶发帧 */
|
||
#define FRAME_TYPE_DIAGNOSTIC 3 /* 诊断帧 */
|
||
#define FRAME_TYPE_RESERVED 4 /* 保留帧 */
|
||
#define FRAME_TYPE_NO_RESPONSE 5 /* 自定义,主机发送无需回应帧 */
|
||
|
||
/* 帧处理状态机 */
|
||
#define FRAME_STATE_IDLE 0 /* 空闲状态 主:等待任务开始 从:固定波特率:等待间隔段 自动波特率:等待间隔段+同步段 */
|
||
#define FRAME_STATE_SEND_SYN 1 /* 主机发送SYN(包括间隔段和同步段) */
|
||
#define FRAME_STATE_RECV_SYN 2 /* 固定波特率:接收同步段0x55 */
|
||
#define FRAME_STATE_RECV_PID 3 /* 接收PID */
|
||
#define FRAME_STATE_RECV_DATA 4 /* 接收数据 */
|
||
#define FRAME_STATE_SEND 5 /* 串口发送 */
|
||
#define FRAME_STATE_SLEEP 6 /* 休眠状态 */
|
||
|
||
/**
|
||
* @brief 计算PID
|
||
* @param id: 输入id
|
||
* @retval 计算后的PID
|
||
*/
|
||
uint8_t calculatePID(uint8_t id)
|
||
{
|
||
uint8_t P0 = 0, P1 = 0;
|
||
|
||
P0 = ((id) ^ (id >> 1) ^ (id >> 2) ^ (id >> 4)) & 0x01;
|
||
P1 = (~((id >> 1) ^ (id >> 3) ^ (id >> 4) ^ (id >> 5))) & 0x01;
|
||
|
||
return ((P1 << 7) | (P0 << 6) | id);
|
||
}
|
||
|
||
/**
|
||
* @brief 计算校验和
|
||
* @param data: 数据指针
|
||
* len: 数据长度
|
||
* @retval checkSum: 校验和
|
||
*/
|
||
uint8_t calculateChecksum(uint8_t *data, uint8_t len)
|
||
{
|
||
uint8_t i;
|
||
uint16_t checkSum = 0;
|
||
|
||
for (i = 0; i < len; i++)
|
||
{
|
||
checkSum += data[i];
|
||
if (checkSum >= 0x100)
|
||
{
|
||
checkSum -= 0xFF;
|
||
}
|
||
}
|
||
checkSum = (~checkSum) & 0xFF;
|
||
|
||
return checkSum;
|
||
}
|
||
|
||
/**
|
||
* @brief LIN slp初始化
|
||
* @param void
|
||
* @retval void
|
||
*/
|
||
void lin_slp_pin_init(void)
|
||
{
|
||
FL_GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||
|
||
LIN_SLP_DISABLE();
|
||
|
||
GPIO_InitStruct.pin = LIN_SLP_PIN;
|
||
GPIO_InitStruct.mode = FL_GPIO_MODE_OUTPUT;
|
||
GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
|
||
GPIO_InitStruct.pull = FL_DISABLE;
|
||
FL_GPIO_Init(LIN_SLP_GPIO, &GPIO_InitStruct);
|
||
}
|
||
|
||
#define Min(a, b) (((a)<(b))?(a):(b))
|
||
#define lin_calc_max_res_timeout_cnt(bitLength, size) (uint16_t)((14*(1+(size))*((bitLength)/TIMER_1US_LOAD))/TIME_BASE_PERIOD + 3 )
|
||
|
||
#if (AUTOBAUD == 1)
|
||
/* 同步处理步骤:目的是不符合要求尽快结束重新判断同步 */
|
||
#define SYN_STEP_WAIT_BREAK 0 /* 等待间隔段,获取间隔段和间隔符时长,与间隔段比较,符合要求转step 1,否则步骤不变 */
|
||
#define SYN_STEP_WAIT_START 1 /* 等待start, 获取起始位长度,与间隔段比较符合要求且占空比为50%转step 2; 否则继续判断是否为间隔段 */
|
||
#define SYN_STEP_WAIT_BIT 2 /* 等待后续bit,4次PWM符合要求之后,转step3,等待stop bit;任意bit不符合要求转step 0 */
|
||
#define SYN_STEP_WAIT_STOP 3 /* 等到stop,判断符合要求结束判断;不符合转step 0 */
|
||
|
||
/* GPTIM中断判断同步相关变量 */
|
||
uint32_t LinSampleValue[20]; /* 记录GPTIM中断来时,当前 sysclk 计数值,需要芯片支持sysclk时钟源为APB */
|
||
uint16_t LinSampleCounter; /* 记录GPTIM PWM中断次数 */
|
||
|
||
uint32_t BitLength; /* 位速率 */
|
||
#endif
|
||
|
||
/* 帧格式 [最大11字节] */
|
||
/* data区内容:受保护ID-1字节; 数据段-0-8字节;校验和-1字节 */
|
||
typedef struct s_lin_frame_type
|
||
{
|
||
uint8_t tx_len;/* 发送长度 */
|
||
uint8_t rx_len;/* 接收长度 */
|
||
uint8_t data[FRAME_DATA_MAX_LEN];
|
||
} lin_frame_data_type;
|
||
|
||
/* 任务处理:等待接收并处理 */
|
||
typedef struct s_lin_task_type
|
||
{
|
||
uint8_t frame_state; /* 帧处理状态机,参照 FRAME_STATE_IDLE 定义 */
|
||
#if (AUTOBAUD == 1)
|
||
uint8_t syn_step; /* 参照 SYN_STEP_WAIT_BREAK */
|
||
#endif
|
||
|
||
/* 帧超时计数,接收到同步段后置起,按照8字节数据计算超时 */
|
||
/* 公式:round((1.4x(10+8x10)xTbit)/Tbase_period) + 3,8为接收字节数,Tbit为单个bit用时,Tbase_period为定时器周期,单位都是us */
|
||
uint16_t frame_timeout_cnt;
|
||
/* 响应超时计数,接收到需要响应的ID后置起,按照实际接收长度计算超时 */
|
||
/* 公式:round((1.4x(10+Nx10)xTbit)/Tbase_period) + 3,N为接收字节数,Tbit为单个bit用时,Tbase_period为定时器周期,单位都是us */
|
||
uint16_t res_frame_timeout_cnt;
|
||
/* Lin总线IDLE超时计数,减为0进入SLEEP状态 */
|
||
uint16_t idle_timeout_cnt;
|
||
lin_frame_data_type lin_frame;/* 帧内容 */
|
||
} lin_task_type;
|
||
|
||
lin_task_type g_lin_task;
|
||
|
||
uint8_t LIN_CMD0_Data[8];
|
||
uint8_t LIN_CMD1_Data[8] = {0x12, 0x34, 0x56, 0x78};
|
||
uint8_t LIN_CMD2_Data[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
|
||
|
||
lin_cmd_packet_t scheduleTable[] =
|
||
{
|
||
/* 用户命令码 */
|
||
{LIN_CMD0, RECEIVE, LIN_CMD0_LENGTH, LIN_CMD0_Data},
|
||
{LIN_CMD1, TRANSMIT, LIN_CMD1_LENGTH, LIN_CMD1_Data},
|
||
{LIN_CMD2, TRANSMIT, LIN_CMD2_LENGTH, LIN_CMD2_Data},
|
||
};
|
||
|
||
/**
|
||
* @brief 接收超时定时器初始化
|
||
* @param void
|
||
* @retval void
|
||
*/
|
||
void lin_timeout_init(void)
|
||
{
|
||
FL_BSTIM16_InitTypeDef timInit;
|
||
|
||
timInit.prescaler = 0; /* 分频系数1 */
|
||
timInit.clockSource = FL_CMU_BSTIM16_CLK_SOURCE_APBCLK; /* 时钟源 */
|
||
timInit.autoReload = TIMER_LOAD_VALUE - 1; /* 自动重装载值 */
|
||
timInit.autoReloadState = FL_DISABLE; /* 预装载preload禁能 */
|
||
FL_BSTIM16_Init(BSTIM16, &timInit);
|
||
|
||
FL_BSTIM16_ClearFlag_Update(BSTIM16);
|
||
NVIC_ClearPendingIRQ(BSTIM_IRQn);
|
||
|
||
/* NVIC中断配置 */
|
||
NVIC_DisableIRQ(BSTIM_IRQn);
|
||
NVIC_SetPriority(BSTIM_IRQn, LIN_BSTIM_IRQ_PRI);
|
||
NVIC_EnableIRQ(BSTIM_IRQn);
|
||
|
||
FL_BSTIM16_EnableIT_Update(BSTIM16);
|
||
|
||
/* 使能定时器 */
|
||
FL_BSTIM16_Enable(BSTIM16);
|
||
}
|
||
|
||
/**
|
||
* @brief lin idle
|
||
* @param void
|
||
* @retval void
|
||
*/
|
||
void lin_goto_idle(void)
|
||
{
|
||
LED2_TOG();
|
||
|
||
g_lin_task.lin_frame.tx_len = 0;
|
||
g_lin_task.lin_frame.rx_len = 0;
|
||
g_lin_task.frame_state = FRAME_STATE_IDLE;
|
||
g_lin_task.idle_timeout_cnt = LIN_IDLE_TIMEOUT;
|
||
|
||
UARTxOp.RxLen = 0;
|
||
UARTxOp.TxLen = 0;
|
||
|
||
#if (AUTOBAUD == 1)
|
||
LinSampleCounter = 0;
|
||
g_lin_task.syn_step = SYN_STEP_WAIT_BREAK; /* 初始化同步步骤 */
|
||
|
||
LIN_UART_RX_GPIO->DFS |= LIN_UART_RX_PIN; /* 引脚重置为GPTIM输入 */
|
||
GPTIM2->CCER |= GPTIM_CCER_CCIP;
|
||
/* 关闭UART接收,使能RX引脚输入捕获中断 */
|
||
FL_UART_DisableRX(LIN_UART);
|
||
GPTIM2->ISR = LIN_GPTIM2_ISR_MASK;
|
||
NVIC_ClearPendingIRQ(GPTIM2_IRQn);
|
||
FL_GPTIM_EnableIT_CC(GPTIM2, FL_GPTIM_CHANNEL_1);/* 使能CC1捕捉中断 */
|
||
NVIC_EnableIRQ(GPTIM2_IRQn);
|
||
#else
|
||
FL_UART_EnableRX(LIN_UART); /* 非自动波特率打开接收 */
|
||
#endif
|
||
|
||
LED2_TOG();
|
||
}
|
||
|
||
|
||
/**
|
||
* @brief lin idle state初始化
|
||
* @param void
|
||
* @retval void
|
||
*/
|
||
__STATIC_INLINE void lin_init_idle_state(void)
|
||
{
|
||
g_lin_task.lin_frame.tx_len = 0;
|
||
g_lin_task.lin_frame.rx_len = 0;
|
||
g_lin_task.frame_state = FRAME_STATE_IDLE;
|
||
g_lin_task.idle_timeout_cnt = LIN_IDLE_TIMEOUT;
|
||
|
||
UARTxOp.RxLen = 0;
|
||
UARTxOp.TxLen = 0;
|
||
|
||
#if (AUTOBAUD == 1)
|
||
LinSampleCounter = 0;
|
||
g_lin_task.syn_step = SYN_STEP_WAIT_BREAK;/* 初始化同步步骤 */
|
||
#else
|
||
|
||
#endif
|
||
}
|
||
|
||
#if (AUTOBAUD == 1)
|
||
|
||
/**
|
||
* @brief 判断两个bit长度是否超过BIT_GAP
|
||
* @param cmp_value: 比较值
|
||
* base_value: 基础值
|
||
* @retval 1: 超过BIT_GAP
|
||
* 0: 不超过BIT_GAP
|
||
*/
|
||
uint8_t check_bit_gap(uint32_t cmp_value, uint32_t base_value)
|
||
{
|
||
uint32_t temp;
|
||
|
||
if (cmp_value > base_value)
|
||
{
|
||
temp = cmp_value - base_value;
|
||
}
|
||
else
|
||
{
|
||
temp = base_value - cmp_value;
|
||
}
|
||
|
||
if (temp > (uint32_t)(base_value * LIN_SYN_BIT_GAP_PERCENTAGE))
|
||
{
|
||
return 1;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
#if (SLEEP_SUPPORT == 1)
|
||
extern uint8_t g_awake_init;
|
||
#endif
|
||
|
||
/**
|
||
* @brief GPTIM2输入捕获中断
|
||
* @note 判断同步间隔段和同步段,计算通信速率
|
||
* @param void
|
||
* @retval void
|
||
*/
|
||
void GPTIM2_IRQHandler(void)
|
||
{
|
||
uint8_t temp, tempFlag;
|
||
volatile uint32_t IC1Value = 0;
|
||
volatile uint32_t IC2Value = 0;
|
||
static uint32_t sumCalcBaud = 0;/* 累计从起始位到第6位的时间 */
|
||
|
||
tempFlag = 0;
|
||
|
||
LED0_TOG();
|
||
|
||
GPTIM2->ISR = LIN_GPTIM2_ISR_MASK;
|
||
|
||
if (LinSampleCounter)
|
||
{
|
||
IC1Value = GPTIM2->CCR1;
|
||
IC2Value = GPTIM2->CCR2;
|
||
}
|
||
#if (SLEEP_SUPPORT == 1)
|
||
else if (g_awake_init)
|
||
{
|
||
g_awake_init = 0;
|
||
|
||
/* 180us为LSCLK下,使能引脚滤波的情况下,产生中断所需要的时间,然后转换成计数值 */
|
||
IC1Value = 180 * TIMER_1US_LOAD + GPTIM2->CCR1;
|
||
IC2Value = 180 * TIMER_1US_LOAD + GPTIM2->CCR2;
|
||
|
||
LinSampleCounter = 1;
|
||
}
|
||
#endif
|
||
|
||
if (LinSampleCounter)
|
||
{
|
||
if ((g_lin_task.frame_state == FRAME_STATE_IDLE) ||
|
||
(g_lin_task.frame_state == FRAME_STATE_SLEEP))
|
||
{
|
||
switch (g_lin_task.syn_step)
|
||
{
|
||
/* 等待间隔段 */
|
||
case SYN_STEP_WAIT_BREAK:
|
||
if (IC2Value < LIN_MIN_BREAK_VALUE)
|
||
{
|
||
/* 间隔段和间隔符长度倍数关系,不足则判定为错误,下降沿作为间隔段开始 */
|
||
LinSampleCounter = 0;
|
||
}
|
||
else
|
||
{
|
||
/* 等待下一个PWM */
|
||
temp = LinSampleCounter - 1;
|
||
temp = temp << 1;
|
||
|
||
LinSampleValue[temp] = IC2Value;
|
||
LinSampleValue[temp + 1] = IC1Value - IC2Value;
|
||
|
||
g_lin_task.syn_step = SYN_STEP_WAIT_START;
|
||
|
||
sumCalcBaud = 0;
|
||
}
|
||
break;
|
||
/* 等待START */
|
||
case SYN_STEP_WAIT_START:
|
||
/* 判断占空比是否符合要求 */
|
||
if (check_bit_gap(IC1Value - IC2Value, IC2Value))
|
||
{
|
||
/* 占空比不符合要求 */
|
||
tempFlag = 2;
|
||
}
|
||
else
|
||
{
|
||
/* 占空比符合要求 */
|
||
if (LinSampleValue[0] < (IC2Value << LIN_BREAK_DELIMITER_TIMES))
|
||
{
|
||
/* 间隔段和起始位长度倍数关系,不足则接着判断是否为新的间隔段 */
|
||
tempFlag = 3;
|
||
}
|
||
else
|
||
{
|
||
/* 间隔段和起始位符合逻辑关系,更新数值 */
|
||
temp = LinSampleCounter - 1;
|
||
temp = temp << 1;
|
||
|
||
LinSampleValue[temp] = IC2Value;
|
||
LinSampleValue[temp + 1] = IC1Value - IC2Value;
|
||
|
||
g_lin_task.syn_step = SYN_STEP_WAIT_BIT;
|
||
|
||
sumCalcBaud += IC1Value;
|
||
}
|
||
}
|
||
|
||
if (tempFlag)
|
||
{
|
||
if (IC2Value < LIN_MIN_BREAK_VALUE)
|
||
{
|
||
/* 间隔段和间隔符长度倍数关系,不足则判定为错误,下降沿作为间隔段开始 */
|
||
LinSampleCounter = 0;
|
||
g_lin_task.syn_step = SYN_STEP_WAIT_BREAK;
|
||
}
|
||
else
|
||
{
|
||
LinSampleCounter = 1;
|
||
|
||
/* 等待下一个PWM */
|
||
temp = LinSampleCounter - 1;
|
||
temp = temp << 1;
|
||
|
||
LinSampleValue[temp] = IC2Value;
|
||
LinSampleValue[temp + 1] = IC1Value - IC2Value;
|
||
|
||
g_lin_task.syn_step = SYN_STEP_WAIT_START;
|
||
|
||
sumCalcBaud = 0;
|
||
}
|
||
}
|
||
|
||
break;
|
||
/* 等待后续位 */
|
||
case SYN_STEP_WAIT_BIT:
|
||
/* 判断占空比是否符合要求 */
|
||
if (check_bit_gap(IC1Value - IC2Value, IC2Value))
|
||
{
|
||
/* 占空比不符合要求 */
|
||
tempFlag = 4;
|
||
}
|
||
else
|
||
{
|
||
/* 占空比符合要求, 判断新的bit与起始位的长度关系 */
|
||
if (check_bit_gap(IC2Value, LinSampleValue[2]))
|
||
{
|
||
/* 超出差距 */
|
||
tempFlag = 5;
|
||
}
|
||
else
|
||
{
|
||
/* 间隔段和起始位符合逻辑关系,更新数值 */
|
||
temp = LinSampleCounter - 1;
|
||
temp = temp << 1;
|
||
|
||
LinSampleValue[temp] = IC2Value;
|
||
LinSampleValue[temp + 1] = IC1Value - IC2Value;
|
||
|
||
sumCalcBaud += IC1Value;
|
||
|
||
if (LinSampleCounter == 5)
|
||
{
|
||
/* 切换为单次上升沿触发直接计数此刻到下一次上升沿的数值 */
|
||
GPTIM2->CCER &= ~GPTIM_CCER_CCIP;
|
||
g_lin_task.syn_step = SYN_STEP_WAIT_STOP;
|
||
|
||
LED1_TOG();
|
||
|
||
sumCalcBaud = sumCalcBaud >> 3;
|
||
sumCalcBaud = sumCalcBaud * LIN_CAPTURE_TIMER_PSC;
|
||
}
|
||
else
|
||
{
|
||
g_lin_task.syn_step = SYN_STEP_WAIT_BIT;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (tempFlag)
|
||
{
|
||
if (IC2Value < LIN_MIN_BREAK_VALUE)
|
||
{
|
||
/* 间隔段和间隔符长度倍数关系,不足则判定为错误,下降沿作为间隔段开始 */
|
||
LinSampleCounter = 0;
|
||
g_lin_task.syn_step = SYN_STEP_WAIT_BREAK;
|
||
}
|
||
else
|
||
{
|
||
LinSampleCounter = 1;
|
||
|
||
/* 等待下一个PWM */
|
||
temp = LinSampleCounter - 1;
|
||
temp = temp << 1;
|
||
|
||
LinSampleValue[temp] = IC2Value;
|
||
LinSampleValue[temp + 1] = IC1Value - IC2Value;
|
||
|
||
g_lin_task.syn_step = SYN_STEP_WAIT_START;
|
||
|
||
sumCalcBaud = 0;
|
||
}
|
||
}
|
||
break;
|
||
/* 等待stop位 */
|
||
case SYN_STEP_WAIT_STOP:
|
||
/* 判断占空比是否符合要求 */
|
||
if (check_bit_gap(IC2Value, LinSampleValue[2]))
|
||
{
|
||
LinSampleCounter = 0;
|
||
g_lin_task.syn_step = SYN_STEP_WAIT_BREAK;
|
||
|
||
GPTIM2->CCER |= GPTIM_CCER_CCIP;/* 切换回双沿 */
|
||
}
|
||
else
|
||
{
|
||
/* 检测同步成功 */
|
||
/* 引脚重置为RX接收 */
|
||
LIN_UART_RX_GPIO->DFS &= ~LIN_UART_RX_PIN;
|
||
|
||
LED1_TOG();
|
||
|
||
/* 设置串口波特率 */
|
||
BitLength = sumCalcBaud;
|
||
|
||
LIN_UART->CSR &= ~UART_CSR_RXEN_Msk;
|
||
LIN_UART->CSR &= ~UART_CSR_TXEN_Msk;
|
||
LIN_UART->BGR = BitLength - 1;
|
||
LIN_UART->CSR |= UART_CSR_TXEN_Msk;
|
||
LIN_UART->ISR = UART_ISR_RXBF_Msk;
|
||
|
||
/* 切换任务状态机 */
|
||
g_lin_task.lin_frame.rx_len = 0;
|
||
g_lin_task.frame_state = FRAME_STATE_RECV_PID;
|
||
|
||
/* 初始化串口接收长度等,使能接收等待接收ID */
|
||
UARTxOp.RxLen = 0 ;
|
||
LIN_UART->CSR |= UART_CSR_RXEN_Msk;
|
||
|
||
LED1_TOG();
|
||
|
||
/* 开始接收,置超时 */
|
||
g_lin_task.frame_timeout_cnt = lin_calc_max_res_timeout_cnt(BitLength, 8);
|
||
|
||
LED1_TOG();
|
||
|
||
/* 关闭GPTIM2中断 */
|
||
/* 关闭CC1捕捉中断 */
|
||
GPTIM2->DIER &= ~LIN_GPTIM2_IER_MASK;
|
||
//NVIC_DisableIRQ(GPTIM2_IRQn);
|
||
|
||
LinSampleCounter = 0;
|
||
g_lin_task.syn_step = SYN_STEP_WAIT_BREAK;
|
||
}
|
||
tempFlag = 6;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
LED1_TOG();
|
||
|
||
LinSampleCounter++;
|
||
}
|
||
#endif
|
||
|
||
/**
|
||
* @brief 定时,用于判断字节间超时
|
||
* @note 12位波特率,如1200-10ms 19.2KHz-625us
|
||
* @param void
|
||
* @retval void
|
||
*/
|
||
void BSTIM_IRQHandler(void)
|
||
{
|
||
if (FL_BSTIM16_IsActiveFlag_Update(BSTIM16))
|
||
{
|
||
FL_BSTIM16_ClearFlag_Update(BSTIM16);
|
||
|
||
switch (g_lin_task.frame_state)
|
||
{
|
||
case FRAME_STATE_IDLE:
|
||
if (0 == g_lin_task.idle_timeout_cnt)
|
||
{
|
||
g_lin_task.frame_state = FRAME_STATE_SLEEP;
|
||
g_lin_task.idle_timeout_cnt = LIN_IDLE_TIMEOUT;
|
||
}
|
||
else
|
||
{
|
||
g_lin_task.idle_timeout_cnt--;
|
||
}
|
||
break;
|
||
case FRAME_STATE_RECV_SYN:
|
||
case FRAME_STATE_RECV_PID:
|
||
case FRAME_STATE_SEND:
|
||
if (0 == g_lin_task.frame_timeout_cnt)
|
||
{
|
||
LED2_TOG();
|
||
|
||
lin_goto_idle();
|
||
}
|
||
else
|
||
{
|
||
g_lin_task.frame_timeout_cnt--;
|
||
}
|
||
break;
|
||
case FRAME_STATE_RECV_DATA:
|
||
if (0 == g_lin_task.res_frame_timeout_cnt)
|
||
{
|
||
LED3_TOG();
|
||
|
||
if (UARTxOp.RxLen > 1)
|
||
{
|
||
UARTxOp.RxLen = 0;
|
||
}
|
||
lin_goto_idle();
|
||
}
|
||
else
|
||
{
|
||
g_lin_task.res_frame_timeout_cnt--;
|
||
}
|
||
break;
|
||
}
|
||
|
||
LED3_TOG();
|
||
}
|
||
}
|
||
/**
|
||
* @brief UART-LIN中断
|
||
* @param void
|
||
* @retval void
|
||
*/
|
||
void LIN_UART_IRQHandler(void)
|
||
{
|
||
uint8_t tmp08;
|
||
static uint8_t PID, i;
|
||
|
||
LED2_TOG();
|
||
|
||
/* 接收错误中断处理 需要注意帧类型错误会同时有RXBF标志,用于判定同步段 */
|
||
if (LIN_UART->ISR & UART_ISR_FERR_Msk)
|
||
{
|
||
tmp08 = LIN_UART->RXBUF;
|
||
|
||
if (tmp08 == LIN_BREAK_BYTE)
|
||
{
|
||
/* 检测到间隔段 */
|
||
g_lin_task.frame_state = FRAME_STATE_RECV_SYN;
|
||
|
||
/* 收到间隔段之后置起超时,等待在超时内收到同步字节0x55 */
|
||
g_lin_task.frame_timeout_cnt = lin_calc_max_res_timeout_cnt(LIN_BIT_TIMER_LOAD, 8);
|
||
}
|
||
else
|
||
{
|
||
/* 帧错误 */
|
||
|
||
lin_goto_idle();
|
||
}
|
||
|
||
LIN_UART->ISR = UART_ISR_FERR_Msk;
|
||
}
|
||
/* 接收中断处理 */
|
||
else if (LIN_UART->ISR & UART_ISR_RXBF_Msk)
|
||
{
|
||
switch (g_lin_task.frame_state)
|
||
{
|
||
/* 固定波特率接收同步阶段 */
|
||
case FRAME_STATE_RECV_SYN:
|
||
/* 接收数据 */
|
||
/* 接收中断标志可通过读取rxreg寄存器清除 */
|
||
tmp08 = LIN_UART->RXBUF;
|
||
UARTxOp.RxLen = 0;
|
||
|
||
if (tmp08 == LIN_SYN_BYTE)
|
||
{
|
||
/* 间隔段之后的第一个字节是0x55 */
|
||
g_lin_task.frame_state = FRAME_STATE_RECV_PID;
|
||
}
|
||
else
|
||
{
|
||
lin_goto_idle();
|
||
}
|
||
break;
|
||
/* 接收PID阶段,判断PID是否有效如有效判定后续行为是发送还是接收 */
|
||
case FRAME_STATE_RECV_PID:
|
||
/* 接收数据 */
|
||
/* 接收中断标志可通过读取rxreg寄存器清除 */
|
||
tmp08 = LIN_UART->RXBUF;
|
||
|
||
UARTxOp.RxBuf[UARTxOp.RxLen] = tmp08;
|
||
UARTxOp.RxLen++;
|
||
|
||
LED2_TOG();
|
||
|
||
for (i = 0; i < TABLE_SIZE; i++)
|
||
{
|
||
if (scheduleTable[i].pid == tmp08)
|
||
{
|
||
PID = tmp08;
|
||
break;
|
||
}
|
||
}
|
||
|
||
LED2_TOG();
|
||
|
||
if (i == TABLE_SIZE)
|
||
{
|
||
/* 无对应命令,不做处理 */
|
||
lin_goto_idle();
|
||
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
if (scheduleTable[i].type == RECEIVE)
|
||
{
|
||
/* 主机发送命令,更新待接收长度,转接收数据阶段 */
|
||
g_lin_task.lin_frame.rx_len = scheduleTable[i].length + 1;
|
||
g_lin_task.frame_state = FRAME_STATE_RECV_DATA;
|
||
|
||
/* 更新响应超时 */
|
||
#if (AUTOBAUD == 1)
|
||
g_lin_task.res_frame_timeout_cnt = lin_calc_max_res_timeout_cnt(BitLength, scheduleTable[i].length);
|
||
#else
|
||
g_lin_task.res_frame_timeout_cnt = lin_calc_max_res_timeout_cnt(LIN_BIT_TIMER_LOAD, scheduleTable[i].length);
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
/* 主机接收命令,更新待发送长度,转发送数据阶段 */
|
||
/* 第一时间发送数据,保证负载率 */
|
||
LIN_UART->TXBUF = scheduleTable[i].data[0];
|
||
|
||
LED2_TOG();
|
||
|
||
#if (CHECKSUM_TYPE == CHECKSUM_TYPE_ENHANCED)
|
||
g_lin_task.lin_frame.data[0] = PID;
|
||
memcpy(&g_lin_task.lin_frame.data[1], scheduleTable[i].data, scheduleTable[i].length);
|
||
g_lin_task.lin_frame.data[scheduleTable[i].length + 1] = calculateChecksum(g_lin_task.lin_frame.data, scheduleTable[i].length + 1);
|
||
|
||
g_lin_task.lin_frame.tx_len = scheduleTable[i].length + 1;
|
||
UARTxOp.TxLen = g_lin_task.lin_frame.tx_len;
|
||
UARTxOp.TxOpc = 1;
|
||
UARTxOp.TxBuf = &g_lin_task.lin_frame.data[1];
|
||
#else
|
||
memcpy(g_lin_task.lin_frame.data, scheduleTable[i].data, scheduleTable[i].length);
|
||
g_lin_task.lin_frame.data[scheduleTable[i].length] = calculateChecksum(g_lin_task.lin_frame.data, scheduleTable[i].length);
|
||
|
||
g_lin_task.lin_frame.tx_len = scheduleTable[i].length + 1;
|
||
UARTxOp.TxLen = g_lin_task.lin_frame.tx_len;
|
||
UARTxOp.TxOpc = 1;
|
||
UARTxOp.TxBuf = g_lin_task.lin_frame.data;
|
||
#endif
|
||
g_lin_task.lin_frame.rx_len = 0;
|
||
g_lin_task.frame_state = FRAME_STATE_SEND;
|
||
}
|
||
}
|
||
|
||
LED2_TOG();
|
||
|
||
break;
|
||
/* 接收数据阶段,直到接收完成才处理 */
|
||
case FRAME_STATE_RECV_DATA:
|
||
if (UARTxOp.RxLen >= g_lin_task.lin_frame.rx_len)
|
||
{
|
||
/* 最后一个字节,第一时间开接收 */
|
||
#if (AUTOBAUD == 1)
|
||
|
||
/* 引脚重置为GPTIM输入 */
|
||
LIN_UART_RX_GPIO->DFS |= LIN_UART_RX_PIN;
|
||
GPTIM2->CCER |= GPTIM_CCER_CCIP;
|
||
|
||
/* 关闭UART接收,使能RX引脚输入捕获中断 */
|
||
GPTIM2->ISR = LIN_GPTIM2_ISR_MASK;
|
||
|
||
/* 使能CC1捕捉中断 */
|
||
GPTIM2->DIER = LIN_GPTIM2_IER_MASK;
|
||
|
||
/* 关闭UART接收 */
|
||
LIN_UART->CSR &= ~UART_CSR_RXEN_Msk;
|
||
#else
|
||
LIN_UART->CSR |= UART_CSR_RXEN_Msk;
|
||
#endif
|
||
|
||
LED2_TOG();
|
||
}
|
||
|
||
/* 接收数据 */
|
||
/* 接收中断标志可通过读取rxreg寄存器清除 */
|
||
tmp08 = LIN_UART->RXBUF;
|
||
|
||
UARTxOp.RxBuf[UARTxOp.RxLen] = tmp08;
|
||
UARTxOp.RxLen++;
|
||
|
||
if (UARTxOp.RxLen >= g_lin_task.lin_frame.rx_len + 1)
|
||
{
|
||
/* 主机主动发送,解析数据 */
|
||
#if (CHECKSUM_TYPE == CHECKSUM_TYPE_ENHANCED)
|
||
if (calculateChecksum(UARTxOp.RxBuf, UARTxOp.RxLen - 1) == UARTxOp.RxBuf[UARTxOp.RxLen - 1])
|
||
{
|
||
LED2_TOG();
|
||
|
||
/* 通过校验 */
|
||
if (scheduleTable[i].length != (UARTxOp.RxLen - 2))
|
||
{
|
||
lin_init_idle_state();
|
||
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
memcpy(scheduleTable[i].data, &UARTxOp.RxBuf[1], scheduleTable[i].length);
|
||
|
||
LED2_TOG();
|
||
}
|
||
}
|
||
#else
|
||
if (calculateChecksum(&UARTxOp.RxBuf[1], UARTxOp.RxLen - 2) == UARTxOp.RxBuf[UARTxOp.RxLen - 1])
|
||
{
|
||
if (scheduleTable[i].length != (UARTxOp.RxLen - 2))
|
||
{
|
||
lin_init_idle_state();
|
||
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
memcpy(scheduleTable[i].data, &UARTxOp.RxBuf[1], scheduleTable[i].length);
|
||
}
|
||
}
|
||
#endif
|
||
lin_init_idle_state();
|
||
}
|
||
break;
|
||
case FRAME_STATE_SEND:
|
||
/* 接收数据 */
|
||
/* 接收中断标志可通过读取rxreg寄存器清除 */
|
||
tmp08 = LIN_UART->RXBUF;
|
||
|
||
if (UARTxOp.TxOpc < UARTxOp.TxLen)
|
||
{
|
||
if (tmp08 != UARTxOp.TxBuf[UARTxOp.TxOpc - 1])
|
||
{
|
||
/* bit错误 */
|
||
#if (AUTOBAUD == 1)
|
||
LIN_UART_RX_GPIO->DFS |= LIN_UART_RX_PIN;/* 引脚重置为GPTIM输入 */
|
||
GPTIM2->CCER |= GPTIM_CCER_CCIP;
|
||
/* 关闭UART接收,使能RX引脚输入捕获中断 */
|
||
GPTIM2->ISR = LIN_GPTIM2_ISR_MASK;
|
||
GPTIM2->DIER = LIN_GPTIM2_IER_MASK;/* 使能CC1捕捉中断 */
|
||
|
||
LIN_UART->CSR &= ~UART_CSR_RXEN_Msk;/* 关闭UART接收 */
|
||
#else
|
||
LIN_UART->CSR |= UART_CSR_RXEN_Msk;
|
||
#endif
|
||
|
||
LED2_TOG();
|
||
|
||
lin_init_idle_state();
|
||
}
|
||
else
|
||
{
|
||
LIN_UART->TXBUF = UARTxOp.TxBuf[UARTxOp.TxOpc]; /* 发送一个数据 */
|
||
UARTxOp.TxOpc++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* 发送完毕,快速切换至接收 */
|
||
#if (AUTOBAUD == 1)
|
||
|
||
/* 引脚重置为GPTIM输入 */
|
||
LIN_UART_RX_GPIO->DFS |= LIN_UART_RX_PIN;
|
||
GPTIM2->CCER |= GPTIM_CCER_CCIP;
|
||
|
||
/* 关闭UART接收,使能RX引脚输入捕获中断 */
|
||
GPTIM2->ISR = LIN_GPTIM2_ISR_MASK;
|
||
|
||
/* 使能CC1捕捉中断 */
|
||
GPTIM2->DIER = LIN_GPTIM2_IER_MASK;
|
||
|
||
/* 关闭UART接收 */
|
||
LIN_UART->CSR &= ~UART_CSR_RXEN_Msk;
|
||
#else
|
||
LIN_UART->CSR |= UART_CSR_RXEN_Msk;
|
||
#endif
|
||
|
||
LED2_TOG();
|
||
|
||
lin_init_idle_state();
|
||
}
|
||
break;
|
||
default:
|
||
/* 接收数据 */
|
||
/* 接收中断标志可通过读取rxreg寄存器清除 */
|
||
tmp08 = LIN_UART->RXBUF;
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* 清除可能的错误中断标志 */
|
||
if (LIN_UART->ISR & UART_ISR_PERR_Msk)
|
||
{
|
||
LIN_UART->ISR = UART_ISR_PERR_Msk;
|
||
}
|
||
if (LIN_UART->ISR & UART_ISR_OERR_Msk)
|
||
{
|
||
LIN_UART->ISR = UART_ISR_OERR_Msk;
|
||
}
|
||
|
||
LED2_TOG();
|
||
}
|
||
|
||
/**
|
||
* @brief lin UART初始化
|
||
* @param void
|
||
* @retval void
|
||
*/
|
||
void lin_uart_init(void)
|
||
{
|
||
/* 初始化uart配置 */
|
||
Uartx_Init(LIN_UART);
|
||
|
||
/* 中断使能 */
|
||
#if (AUTOBAUD == 1)
|
||
#else
|
||
/* 接收错误中断使能,用于同步判断 */
|
||
FL_UART_EnableIT_RXError(LIN_UART);
|
||
#endif
|
||
/* 接收中断使能 */
|
||
FL_UART_EnableIT_RXBuffFull(LIN_UART);
|
||
|
||
FL_UART_EnableTX(LIN_UART);
|
||
#if (AUTOBAUD == 1)
|
||
#else
|
||
FL_UART_EnableRX(LIN_UART);
|
||
#endif
|
||
}
|
||
|
||
/**
|
||
* @brief lin 任务初始化
|
||
* @param void
|
||
* @retval void
|
||
*/
|
||
void lin_task_init(void)
|
||
{
|
||
uint8_t i;
|
||
|
||
/* 状态机相关初始化 */
|
||
g_lin_task.frame_state = FRAME_STATE_IDLE;
|
||
g_lin_task.idle_timeout_cnt = LIN_IDLE_TIMEOUT;
|
||
|
||
/* 帧数据初始化 */
|
||
g_lin_task.lin_frame.rx_len = 0;
|
||
g_lin_task.lin_frame.tx_len = 0;
|
||
|
||
/* 根据cmd计算pid */
|
||
for (i = 0; i < TABLE_SIZE; i++)
|
||
{
|
||
scheduleTable[i].pid = calculatePID(scheduleTable[i].cmd);
|
||
}
|
||
}
|
||
|
||
#if (AUTOBAUD == 1)
|
||
/**
|
||
* @brief GPTIM初始化
|
||
* @param void
|
||
* @retval void
|
||
*/
|
||
void GPTIM_Init(void)
|
||
{
|
||
FL_GPTIM_InitTypeDef timInit;
|
||
FL_GPTIM_IC_InitTypeDef timICInit;
|
||
FL_GPTIM_SlaveInitTypeDef timSlaveInit;
|
||
FL_GPIO_InitTypeDef gpioInit = {0};
|
||
|
||
gpioInit.pin = FL_GPIO_PIN_0;
|
||
gpioInit.mode = FL_GPIO_MODE_DIGITAL;
|
||
gpioInit.outputType = FL_GPIO_OUTPUT_PUSHPULL;
|
||
gpioInit.pull = FL_DISABLE;
|
||
gpioInit.remapPin = FL_ENABLE;
|
||
FL_GPIO_Init(GPIOD, &gpioInit);
|
||
|
||
timInit.prescaler = LIN_CAPTURE_TIMER_PSC - 1; /* 分频系数1 */
|
||
timInit.counterMode = FL_GPTIM_COUNTER_DIR_UP; /* 向上计数 */
|
||
timInit.autoReload = 65535; /* 自动重装载值65536 */
|
||
timInit.clockDivision = FL_GPTIM_CLK_DIVISION_DIV1; /* 死区和滤波分频 */
|
||
timInit.autoReloadState = FL_ENABLE; /* 预装载preload使能 */
|
||
FL_GPTIM_Init(GPTIM2, &timInit);
|
||
|
||
timSlaveInit.slaveMode = FL_GPTIM_SLAVE_MODE_TRGI_RISE_RST; /* 从机复位模式,用于配制PWM输入捕获 */
|
||
timSlaveInit.triggerSrc = FL_GPTIM_TIM_TS_TI1FP1; /* 触发源选择 TI1FP1 */
|
||
timSlaveInit.triggerDelay = FL_DISABLE; /* TRGI延迟禁止 */
|
||
FL_GPTIM_SlaveMode_Init(GPTIM2, &timSlaveInit);
|
||
|
||
timICInit.ICPolarity = FL_GPTIM_IC_POLARITY_INVERT; /* 下降沿捕获 */
|
||
timICInit.ICActiveInput = FL_GPTIM_CHANNEL_MODE_INPUT_NORMAL; /* CC1配置为输入,IC1映射到TI1 */
|
||
timICInit.ICPrescaler = FL_GPTIM_IC_PSC_DIV1; /* 输入捕捉分频 */
|
||
timICInit.ICFilter = FL_GPTIM_IC_FILTER_DIV1; /* 输入捕捉滤波配置 */
|
||
timICInit.captureState = FL_ENABLE; /* 使能CC1通道 */
|
||
FL_GPTIM_IC_Init(GPTIM2, FL_GPTIM_CHANNEL_1, &timICInit);
|
||
|
||
timICInit.ICPolarity = FL_GPTIM_IC_POLARITY_NORMAL; /* 上升沿捕获 */
|
||
timICInit.ICActiveInput = FL_ATIM_CHANNEL_MODE_INPUT_CROSSOVER; /* CC1配置为输入,IC1映射到TI1 */
|
||
FL_GPTIM_IC_Init(GPTIM2, FL_GPTIM_CHANNEL_2, &timICInit);
|
||
|
||
GPTIM2->ISR = LIN_GPTIM2_ISR_MASK;
|
||
|
||
/* 中断优先级配置 */
|
||
NVIC_ClearPendingIRQ(GPTIM2_IRQn);
|
||
NVIC_DisableIRQ(GPTIM2_IRQn);
|
||
NVIC_SetPriority(GPTIM2_IRQn, LIN_GPITM2_IRQ_PRI);
|
||
NVIC_EnableIRQ(GPTIM2_IRQn);
|
||
|
||
FL_GPTIM_ClearFlag_CC(GPTIM2, FL_GPTIM_CHANNEL_1); /* 清除CC1捕捉标志 */
|
||
FL_GPTIM_EnableIT_CC(GPTIM2, FL_GPTIM_CHANNEL_1); /* 使能CC1捕捉中断 */
|
||
|
||
FL_GPTIM_Enable(GPTIM2); /* 使能定时器 */
|
||
}
|
||
#endif
|
||
|
||
/**
|
||
* @brief LIN初始化
|
||
* @param void
|
||
* @retval void
|
||
*/
|
||
void lin_init(void)
|
||
{
|
||
lin_task_init();
|
||
lin_slp_pin_init();
|
||
lin_uart_init();
|
||
#if (AUTOBAUD == 1)
|
||
GPTIM_Init();
|
||
#endif
|
||
lin_timeout_init();
|
||
}
|
||
|
||
#if (SLEEP_SUPPORT == 1)
|
||
|
||
/**
|
||
* @brief LIN休眠前初始化
|
||
* @param void
|
||
* @retval void
|
||
*/
|
||
void lin_sleep_init(void)
|
||
{
|
||
/* 清除和关闭非唤醒源中断 */
|
||
Close_And_ClearIRQ(BSTIM_IRQn);
|
||
|
||
/* 关闭UART接收功能 */
|
||
LIN_UART->CSR &= ~UART_CSR_RXEN_Msk;
|
||
Close_And_ClearIRQ(LIN_UART_IRQType);
|
||
|
||
#if (AUTOBAUD == 1)
|
||
|
||
/* 禁能定时器 */
|
||
GPTIM2->CR1 &= ~GPTIM_CR1_CEN_Msk;
|
||
/* 提前配置唤醒后状态 */
|
||
GPTIM2->CCER |= GPTIM_CCER_CCIP;
|
||
|
||
Close_And_ClearIRQ(GPTIM2_IRQn);
|
||
#else
|
||
|
||
#endif
|
||
}
|
||
|
||
/**
|
||
* @brief LIN唤醒后初始化
|
||
* @param void
|
||
* @retval void
|
||
*/
|
||
void lin_awake_init(void)
|
||
{
|
||
g_lin_task.lin_frame.tx_len = 0;
|
||
g_lin_task.lin_frame.rx_len = 0;
|
||
g_lin_task.frame_state = FRAME_STATE_IDLE;
|
||
g_lin_task.idle_timeout_cnt = LIN_IDLE_TIMEOUT;
|
||
|
||
UARTxOp.RxLen = 0;
|
||
UARTxOp.TxLen = 0;
|
||
|
||
#if (AUTOBAUD == 1)
|
||
LinSampleCounter = 0;
|
||
|
||
/* 初始化同步步骤 */
|
||
g_lin_task.syn_step = SYN_STEP_WAIT_BREAK;
|
||
|
||
g_awake_init = 1;
|
||
NVIC_EnableIRQ(LIN_UART_IRQType);
|
||
#endif
|
||
|
||
/* 使能非唤醒源中断 */
|
||
NVIC_EnableIRQ(BSTIM_IRQn);
|
||
}
|
||
|
||
/**
|
||
* @brief LIN sleep判断
|
||
* @param void
|
||
* @retval 1: Sleep
|
||
* 0: Wake
|
||
*/
|
||
uint8_t lin_is_sleep(void)
|
||
{
|
||
if (g_lin_task.frame_state == FRAME_STATE_SLEEP)
|
||
{
|
||
return 1;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
#endif /* End #if (SLEEP_SUPPORT == 1) */
|
||
|
||
|
||
void GetMasterData(uint8_t *buf)
|
||
{
|
||
|
||
}
|
||
|