valve_debugging/User/driver/ch438q.c

295 lines
8.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "ch438q.h"
#include "fsmc.h"
#include "ht1200m.h"
#define CH438_CLK 1843200 /* CH438的内部时钟频率默认外部晶振的12分频 */
const uint8_t offsetadd[] = {
0x00,
0x10,
0x20,
0x30,
0x08,
0x18,
0x28,
0x38,
}; /* 串口号的偏移地址 */
const uint8_t Interruptnum[] = {
0x01,
0x02,
0x04,
0x08,
0x10,
0x20,
0x40,
0x80,
}; /* SSR寄存器中断号对应值 */
uint8_t receive_data_buff[256];
uint8_t receive_data_len;
static void ch438_tranconfig(uint8_t uart_num);
static void ch438_set_baudrate(uint8_t uart_num, uint32_t baudrate);
/**
* @brief 配置串口通信参数
*
* 设置串口通讯的格式8个数据位1个停止位1个校验位奇校验并设置FIFO模式触发点为112个字节。
*
* @param uart_num 串口编号
*/
void ch438_tranconfig(uint8_t uart_num)
{
// 设置串口通讯的格式8个数据位1个停止位1个校验位奇校验
ch438_write_reg(offsetadd[uart_num] | REG_LCR_ADDR, BIT_LCR_PAREN | BIT_LCR_WORDSZ1 | BIT_LCR_WORDSZ0, 1);
/* 设置FIFO模式触发点为112个字节 */
ch438_write_reg(offsetadd[uart_num] | REG_FCR_ADDR, BIT_FCR_RECVTG0 | BIT_FCR_RECVTG1 | BIT_FCR_FIFOEN, 1);
}
/**
* @brief 设置CH438 UART的波特率
*
* 通过修改CH438 UART的波特率寄存器来设置指定UART的波特率。
*
* @param uart_num UART编号
* @param baudrate 需要设置的波特率
*/
static void ch438_set_baudrate(uint8_t uart_num, uint32_t baudrate)
{
uint8_t dlab = 0;
uint16_t bandspeed;
dlab = ch438_read_reg(offsetadd[uart_num] | REG_LCR_ADDR, 1);
dlab |= 0x80; // 置LCR寄存器的DLAB位为1
ch438_write_reg(offsetadd[uart_num] | REG_LCR_ADDR, dlab, 1);
bandspeed = CH438_CLK / 16 / baudrate;
ch438_write_reg(offsetadd[uart_num] | REG_DLL_ADDR, (uint8_t)bandspeed, 1);
ch438_write_reg(offsetadd[uart_num] | REG_DLM_ADDR, (uint8_t)(bandspeed >> 8), 1);
dlab &= 0x7F; // 置LCR寄存器的DLAB位为0
ch438_write_reg(offsetadd[uart_num] | REG_LCR_ADDR, dlab, 1);
}
/**
* @brief 向CH438寄存器写入数据
*
* 该函数用于向CH438芯片的指定寄存器写入指定大小的数据。
*
* @param addr 要写入的寄存器地址
* @param data 要写入的数据
* @param size 要写入的数据大小(以字节为单位)
*/
void ch438_write_reg(uint8_t addr, uint8_t data, uint8_t size)
{
uint32_t *address = (uint32_t *)(0x60000000 + addr);
HAL_SRAM_Write_8b(&hsram1, address, &data, size);
}
/**
* @brief 从CH438的寄存器中读取数据
*
* 从指定的地址读取指定大小的数据。
*
* @param addr 寄存器地址
* @param size 要读取的数据大小(以字节为单位)
*
* @return 读取到的数据
*/
uint8_t ch438_read_reg(uint8_t addr, uint8_t size)
{
uint8_t data = 0;
uint32_t *address = (uint32_t *)(0x60000000 + addr);
HAL_SRAM_Read_8b(&hsram1, address, &data, size);
return data;
}
void ch438_test(void)
{
uint8_t reg_data[16] = {0};
reg_data[0] = 0xAA;
ch438_write_reg(offsetadd[0] | REG_SCR_ADDR, reg_data[0], 1);
reg_data[1] = ch438_read_reg(offsetadd[0] | REG_SCR_ADDR, 1);
reg_data[2] = ch438_read_reg(offsetadd[0] | REG_IER_ADDR, 1);
reg_data[3] = ch438_read_reg(offsetadd[0] | REG_IIR_ADDR, 1);
reg_data[4] = ch438_read_reg(offsetadd[0] | REG_LCR_ADDR, 1);
}
/**
* @brief 重置所有UART
*
* 该函数用于重置所有UART设备。
*
* @return 无
*/
void ch438_reset_all_uart(void)
{
for (uint8_t i = 0; i < 8; i++)
{
ch438_write_reg(offsetadd[CH438_UART0 + i] | REG_IER_ADDR, BIT_IER_RESET, 1);
}
}
/**
* @brief 关闭指定UART的电源
*
* 关闭指定UART的电源使UART进入低功耗模式。
*
* @param uart_num UART编号取值范围为0到3
*/
void ch438_close_uart(uint8_t uart_num)
{
ch438_write_reg(offsetadd[uart_num] | REG_IER_ADDR, BIT_IER_LOWPOWER, 1);
}
/**
* @brief 关闭所有UART串口
*
* 关闭CH438芯片上的所有UART串口。
*
* 具体操作是向CH438的IER寄存器中断使能寄存器写入特定值
* 将SLP休眠模式使能位和LOWPOWER低功耗模式使能位同时设置为1
* 以关闭时钟振荡器并使所有UART串口进入休眠状态。
*/
void ch438_close_all_uart(void)
{
ch438_write_reg(offsetadd[CH438_UART0] | REG_IER_ADDR, BIT_IER_LOWPOWER | BIT_IER_SLP, 1); // 数据手册描述SLP和LOWPOWER同时为1关闭时钟振荡器所有串口进入休眠
}
/**
* @brief 初始化UART通信
*
* 该函数用于初始化指定的UART端口并设置其波特率。
*
* @param uart_num UART端口号
* @param baudrate 波特率
*/
void ch438_init_uart(uint8_t uart_num, uint32_t baudrate)
{
ch438_tranconfig(uart_num);
ch438_set_baudrate(uart_num, baudrate);
}
/**
* @brief 检查并返回中断标识寄存器IIR的值
*
* 该函数通过UART编号读取并返回中断标识寄存器IIR的值。
*
* @param uart_num UART编号用于指定要读取的UART接口
*
* @return 返回中断标识寄存器IIR的值
*/
uint8_t ch438_check_iir_reg(uint8_t uart_num)
{
return ch438_read_reg(offsetadd[uart_num] | REG_IIR_ADDR, 1);
}
/**
* @brief 初始化CH438的配置
*
* 该函数用于初始化CH438芯片的配置包括中断使能寄存器和调制解调器控制寄存器的设置。
*
* @param uart_num UART编号用于指定要初始化的UART通道
*/
void ch438_init_config(uint8_t uart_num)
{
/* CH438打开BIT_IER_IETHRE会产生一个发送空中断 */
ch438_write_reg(offsetadd[uart_num] | REG_IER_ADDR, BIT_IER_IELINES | BIT_IER_IETHRE | BIT_IER_IERECV, 1);
ch438_check_iir_reg(uart_num);
ch438_write_reg(offsetadd[uart_num] | REG_MCR_ADDR, BIT_MCR_OUT2, 1);
}
void ch438_send_data(uint8_t uart_num, uint8_t *data, uint16_t len)
{
HART1_RTS_SEND;
for (uint8_t i = 0; i < len; i++)
{
ch438_write_reg(offsetadd[uart_num] | REG_THR_ADDR, data[i], 1);
}
}
uint8_t ch438_recv_data(uint8_t uart_num, uint8_t *data)
{
uint8_t data_len = 0;
uint8_t *receive_data;
receive_data = data;
uint16_t time_out = 1000;
// 等待数据准备好
while ((ch438_read_reg(offsetadd[uart_num] | REG_LSR_ADDR, 1) & BIT_LSR_DATARDY) == 0)
{
time_out--;
if (time_out == 0)
{
break;
}
}
while ((ch438_read_reg(offsetadd[uart_num] | REG_LSR_ADDR, 1) & BIT_LSR_DATARDY))
{
*receive_data = ch438_read_reg(offsetadd[uart_num] | REG_RBR_ADDR, 1);
receive_data++;
data_len++;
if (data_len == 112)
{
break;
}
}
return data_len;
}
void ch438_interrupt_handler(void)
{
uint8_t gInterruptStatus; /* 全局中断状态 */
uint8_t InterruptStatus; /* 独立串口中断状态 */
uint8_t i;
gInterruptStatus = ch438_read_reg(REG_SSR_ADDR, 1);
if (!gInterruptStatus)
{
return;
}
for (i = 0; i < 8; i++)
{
if (gInterruptStatus & Interruptnum[i]) /* 检测哪个串口发生中断 */
{
InterruptStatus = ch438_read_reg(offsetadd[i] | REG_IIR_ADDR, 1) & 0x0f; /* 读串口的中断状态 */
switch (InterruptStatus)
{
case INT_NOINT: /* 没有中断 */
break;
case INT_THR_EMPTY: /* THR空中断 */
HART1_RTS_RECEIVE;
break;
case INT_RCV_OVERTIME: /* 接收超时中断 */
receive_data_len = ch438_recv_data(i, receive_data_buff);
ch438_send_data(i, receive_data_buff, receive_data_len);
break;
case INT_RCV_SUCCESS: /* 接收数据可用中断 */
receive_data_len = ch438_recv_data(i, receive_data_buff);
ch438_send_data(i, receive_data_buff, receive_data_len);
break;
case INT_RCV_LINES: /* 接收线路状态中断 */
ch438_read_reg(offsetadd[i] | REG_LSR_ADDR, 1);
break;
case INT_MODEM_CHANGE: /* MODEM输入变化中断 */
ch438_read_reg(offsetadd[i] | REG_MSR_ADDR, 1);
break;
default:
break;
}
}
}
}
void ch438_init(void)
{
ch438_reset_all_uart();
HAL_Delay(250);
ch438_init_uart(CH438_UART0, 1200);
ch438_init_config(CH438_UART0);
}