579 lines
18 KiB
C
Raw Permalink Normal View History

2025-02-18 15:40:42 +08:00
#include "ex_mcu_uart.h"
#if TCFG_EX_MCU_ENABLE
#define LOG_TAG_CONST EX_MCU_UART
#define LOG_TAG "[ex_mcu_uart]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
//=======================================================================//
// 模块操作部分 //
//=======================================================================//
static struct ex_mcu_uart_handle ex_mcu_uart_hdl;
#define __this (&ex_mcu_uart_hdl)
//标志进出推代码流程,用于屏蔽串口中断
static u8 ex_mcu_enter_flag = 0;
//=======================================================================//
// 串口收发部分 //
//=======================================================================//
volatile u8 send_busy;
//串口时钟和串口超时时钟是分开的
#define UART_SRC_CLK clk_get("uart")
#define UART_OT_CLK clk_get("lsb")
//=======================================================================//
// 复位操作部分 //
//=======================================================================//
u8 ucEx_mcu_reset(void)
{
return true;
}
//=======================================================================//
// 文件系统操作部分 //
//=======================================================================//
void *vEx_mcu_file_open(const char *file_path)
{
u32 err = 0;
FILE *pvfile = 0;
pvfile = fopen(file_path, "r");
log_debug("pvfile:0x%x\n", pvfile);
if (pvfile == NULL) {
log_error("%s:%d, vfs open %s err\n", __func__, __LINE__, file_path);
return -ENOENT;
}
//获取EX_MCU_FILE的cache地址
struct vfs_attr code_attr = {0};
if (fget_attrs(pvfile, &code_attr) != 0) {
log_error("%s:%d, get_attrs %s err\n", __func__, __LINE__, file_path);
return -ENOENT;
}
__this->file_cpu_acess_begin = boot_info.sfc.app_addr + code_attr.sclust;
log_info("attr.attr = 0x%x, attr.fsize = 0x%x, attr.sclust = 0x%x, cpu_acess_begin = 0x%x\n", code_attr.attr, code_attr.fsize, code_attr.sclust, __this->file_cpu_acess_begin);
fclose(pvfile);
//返回一个flash地址变量指针进行读操作
return (void *)&__this->file_cpu_acess_begin;
}
u32 ulEx_mcu_file_read(void *file, void *buf, u32 len)
{
if (buf == NULL) {
log_error("%s:%d, need read buf is null\n", __func__, __LINE__);
return 0;
}
log_debug("%s:%d, file: 0x%x\n", __func__, __LINE__, (u8 *)(*(u32 *)(file)));
//void*先转换为32位指针再取32位指针内容得到flash地址
memcpy(buf, (u8 *)(*(u32 *)(file)), len);
return len;
}
u32 ulEx_mcu_file_seek(void *file, u32 offset)
{
*(u32 *)file = *(u32 *)file + offset;
log_debug("%s:%d, file: 0x%x\n", __func__, __LINE__, (*(u32 *)(file)));
return offset;
}
//=======================================================================//
// 带os串口收发操作部分 //
//=======================================================================//
#if TCFG_EX_MCU_OS_ENABLE
//OS调度使用lsb时钟源进行定时,未添加外部接口
static void udelay(u32 usec)
{
JL_TIMER0->CON = BIT(14);
JL_TIMER0->CNT = 0;
JL_TIMER0->PRD = clk_get("lsb") / 1000000L * usec;//1us
JL_TIMER0->CON = BIT(0); //lsb clk
while ((JL_TIMER0->CON & BIT(15)) == 0);
JL_TIMER0->CON = BIT(14);
}
___interrupt
static void ex_mcu_uart_isr(void)
{
if ((__this->UART->CON0 & BIT(2)) && (__this->UART->CON0 & BIT(15))) {
__this->UART->CON0 |= BIT(13);
send_busy = 0;
//*****************接收部分***************
//发送成功,把引脚拉低设为接收模式
gpio_direction_input(__this->data->io_port);
//开启接收功能
__this->UART->CON1 &= ~BIT(4);
if (__this->UART == JL_UART0) {
gpio_set_fun_input_port(__this->data->io_port, PFI_UART0_RX);
} else if (__this->UART == JL_UART1) {
gpio_set_fun_input_port(__this->data->io_port, PFI_UART1_RX);
} else {
gpio_set_fun_input_port(__this->data->io_port, PFI_UART2_RX);
}
__this->UART->CON0 = BIT(13) | BIT(12) | BIT(10);
__this->UART->CON0 |= BIT(6) | BIT(3) | BIT(1) | BIT(0);
log_debug("%s:%d,tx mode to rx\n", __func__, __LINE__);
}
//*****************接收中断***************
if ((__this->UART->CON0 & BIT(3)) && (__this->UART->CON0 & BIT(14))) {
//接收成功
__this->UART->CON0 |= BIT(7);//DMA模式
__this->UART->CON0 |= BIT(12) ;
__this->UART->CON0 |= BIT(10) ;
/* log_debug("%s:%d,rx cnt:%d\n", __func__, __LINE__, __this->UART->HRXCNT); */
}
//屏蔽串口中断
if (ex_mcu_enter_flag == 1) {
//发送和接收都发信号量
os_sem_post(__this->data->sem_tx_rx);
}
}
u8 ucEx_mcu_tx_rx_init(const struct ex_mcu_platform_data *data)
{
u32 uart_timeout;
__this->data = data;
//动态申请内存空间注意exit要释放
__this->data->ex_mcu_buf = (u8 *)malloc(EX_MCU_APP_BUF_SIZE);
ASSERT(data);
if (!(JL_UART0->CON0 & BIT(0))) {
JL_UART0->CON0 = BIT(13) | BIT(12) | BIT(10);
request_irq(IRQ_UART0_IDX, 2, ex_mcu_uart_isr, 0);
__this->UART = JL_UART0;
log_info("Ex_mcu using JL_UART0\n");
} else if (!(JL_UART1->CON0 & BIT(0))) {
JL_UART1->CON0 = BIT(13) | BIT(12) | BIT(10);
request_irq(IRQ_UART1_IDX, 2, ex_mcu_uart_isr, 0);
__this->UART = JL_UART1;
log_info("Ex_mcu using JL_UART1\n");
} else if (!(JL_UART2->CON0 & BIT(0))) {
JL_UART2->CON0 = BIT(13) | BIT(12) | BIT(10);
request_irq(IRQ_UART2_IDX, 2, ex_mcu_uart_isr, 0);
__this->UART = JL_UART2;
log_info("Ex_mcu using JL_UART2\n");
} else {
ASSERT(0, "uart all used!\n");
}
send_busy = 0;
uart_timeout = 20 * 1000000 / __this->data->hand_baudrate;
// 6 rx读dma 3 rx中断 2 tx中断 1 tx使能 0tx使能
__this->UART->CON0 = BIT(13) | BIT(12) | BIT(6) | BIT(10) | BIT(3) | BIT(2) | BIT(1) | BIT(0); //占用该串口,不被其他模块使用
/* __this->UART->OTCNT = uart_timeout * (UART_OT_CLK / 1000000); */
__this->UART->BAUD = (UART_SRC_CLK / __this->data->hand_baudrate) / 4 - 1;
__this->baudrate = __this->data->hand_baudrate;
gpio_set_pull_down(__this->data->io_port, 0);
gpio_set_pull_up(__this->data->io_port, 1);
gpio_set_die(__this->data->io_port, 1);
gpio_direction_input(__this->data->io_port);
return true;
}
u32 vEx_mcu_uart_tx_buf_client(u8 *uart_dma_buf, u32 dma_buf_len)
{
__this->UART->CON0 |= BIT(13) | BIT(12) | BIT(10) | BIT(0);//清空TX Pending/RX Pending/OTPND打开发送使能
gpio_direction_output(__this->data->io_port, 1);
__this->UART->CON1 |= BIT(4);
if (__this->UART == JL_UART0) {
gpio_set_fun_output_port(__this->data->io_port, FO_UART0_TX, 1, 1);
} else if (__this->UART == JL_UART1) {
gpio_set_fun_output_port(__this->data->io_port, FO_UART1_TX, 1, 1);
} else {
gpio_set_fun_output_port(__this->data->io_port, FO_UART2_TX, 1, 1);
}
u32 data_addr = (u32)uart_dma_buf;
if (data_addr % 4) {//4byte对齐
ASSERT(0, "%s: unaligned accesses!", __func__);
}
send_busy = 1;
__this->UART->TXADR = data_addr;
__this->UART->TXCNT = dma_buf_len;
while (!(__this->UART->CON0 & BIT(15)));
send_busy = 0;
__this->UART->CON0 |= BIT(13);
gpio_direction_input(__this->data->io_port);
}
void vEx_mcu_uart_tx_buf(u8 *uart_dma_buf, u32 dma_buf_len)
{
__this->UART->CON0 = BIT(13) | BIT(12) | BIT(10);
gpio_direction_output(__this->data->io_port, 1);
//关闭接收功能
__this->UART->CON1 |= BIT(4);
if (__this->UART == JL_UART0) {
gpio_set_fun_output_port(__this->data->io_port, FO_UART0_TX, 1, 1);
} else if (__this->UART == JL_UART1) {
gpio_set_fun_output_port(__this->data->io_port, FO_UART1_TX, 1, 1);
} else {
gpio_set_fun_output_port(__this->data->io_port, FO_UART2_TX, 1, 1);
}
u32 data_addr = (u32)uart_dma_buf;
if (data_addr % 4) {//4byte对齐
ASSERT(0, "%s: unaligned accesses!", __func__);
}
//打开发送中断
__this->UART->CON0 = BIT(2) | BIT(0);
__this->UART->TXADR = data_addr;
__this->UART->TXCNT = dma_buf_len;
send_busy = 1;
}
//初始化内存
u8 ucEx_mcu_uart_rx_init(u8 *uart_dma_buf, u32 dma_buf_len/* , u32 timeout*/)
{
memset((void *)uart_dma_buf, 0, sizeof(uart_dma_buf));
__this->UART->RXSADR = (u32)uart_dma_buf;
__this->UART->RXEADR = (u32)((((u32)uart_dma_buf + dma_buf_len) + 3) / 4 * 4);
__this->UART->RXCNT = dma_buf_len;
return true;
}
u32 ulEx_mcu_uart_rx_buf_client(u8 *uart_dma_buf, u32 dma_buf_len, u32 timeout)
{
JL_PORTA->OUT |= BIT(2);
u32 ret = 0;
__this->UART->CON0 = BIT(13) | BIT(12) | BIT(10);
gpio_direction_input(__this->data->io_port);
gpio_set_die(__this->data->io_port, 1);
__this->UART->CON1 &= ~BIT(4);
if (__this->UART == JL_UART0) {
gpio_set_fun_input_port(__this->data->io_port, PFI_UART0_RX);
} else if (__this->UART == JL_UART1) {
gpio_set_fun_input_port(__this->data->io_port, PFI_UART1_RX);
} else {
gpio_set_fun_input_port(__this->data->io_port, PFI_UART2_RX);
}
/* memset((void *)uart_dma_buf, 0, sizeof(uart_dma_buf)); */
__this->UART->RXSADR = (u32)uart_dma_buf;
__this->UART->RXEADR = (u32)((((u32)uart_dma_buf + dma_buf_len) + 3) / 4 * 4);
__this->UART->RXCNT = dma_buf_len;
__this->UART->CON0 |= BIT(6);
__this->UART->CON0 |= BIT(13) | BIT(12) | BIT(10) | BIT(1);
//轮询检查是否收到内容
//TODO
/* printf("__this->UART->CON0 & (BIT(14)) = %d",__this->UART->CON0 & (BIT(14)) ); */
/* timeout = 1000; */
/* __asm__ volatile("csync"); */
/* while (timeout--) { */
/* __asm__ volatile("csync"); */
/* if ((__this->UART->CON0 & BIT(14))) { */
/* [> log_debug("CAAAAAAAAAC\n"); <] */
/* ret = dma_buf_len; */
/* break; */
/* } */
/* //1ms */
/* //log_debug("\n%d\n",timeout); */
/* } */
/* //time_out == 0 意味等待时间超时 */
/* if (timeout == 0) */
/* { */
/* log_debug("error\n"); */
/* return -1; */
/* } */
timeout = 1000;
while (timeout && ((__this->UART->CON0 & BIT(14)) == 0)) {
timeout--;
__asm__ volatile("csync");
/* printf("CAAAAAAAAAC\n"); */
/* wdt_clear(); */
}
__this->UART->CON0 |= BIT(12) | BIT(10);
udelay(200);
/* printf_buf((u8 *)uart_dma_buf, dma_buf_len); */
ret = dma_buf_len;
return ret;
}
u32 ulEx_mcu_uart_rx_buf(void)
{
//读当前串口接收数据的个数
return __this->UART->HRXCNT;
}
//目前没有用到
void vEx_mcu_os_delay(unsigned int t)
{
os_time_dly(t);
}
#else
//=======================================================================//
// 裸板串口操作部分 //
//=======================================================================//
void vEx_mcu_udelay(u32 usec)
{
//可在此处添加裸板的自定义代码需尽量保证延时为10ms对应到总函数接口的retry_timeout,单位10ms
JL_TIMER0->CON = BIT(14);
JL_TIMER0->CNT = 0;
JL_TIMER0->PRD = clk_get("timer") / 100L * usec; //10ms
JL_TIMER0->CON = BIT(0) | BIT(2) | BIT(6); //sys clk
//针对串口中断进行修改,一有串口消息就退出
while ((JL_TIMER0->CON & BIT(15)) == 0) {
//延时的时候起串口中断就退出
if (__this->UART->CON0 & BIT(14)) {
break;
}
if (__this->UART->CON0 & BIT(15)) {
break;
}
clr_wdt();
}
JL_TIMER0->CON = BIT(14);
}
u8 ucEx_mcu_tx_rx_init(const struct ex_mcu_platform_data *data)
{
u32 uart_timeout;
__this->data = data;
ASSERT(data);
if (!(JL_UART0->CON0 & BIT(0))) {
JL_UART0->CON0 = BIT(13) | BIT(12) | BIT(10);
/* request_irq(IRQ_UART0_IDX, 2, uart_isr, 0); */
__this->UART = JL_UART0;
log_info("Ex_mcu using JL_UART0\n");
} else if (!(JL_UART1->CON0 & BIT(0))) {
JL_UART1->CON0 = BIT(13) | BIT(12) | BIT(10);
/* request_irq(IRQ_UART1_IDX, 2, uart_isr, 0); */
__this->UART = JL_UART1;
log_info("Ex_mcu using JL_UART1\n");
} else if (!(JL_UART2->CON0 & BIT(0))) {
JL_UART2->CON0 = BIT(13) | BIT(12) | BIT(10);
/* request_irq(IRQ_UART2_IDX, 2, uart_isr, 0); */
__this->UART = JL_UART2;
log_info("Ex_mcu using JL_UART2\n");
} else {
ASSERT(0, "uart all used!\n");
}
send_busy = 0;
uart_timeout = 20 * 1000000 / __this->data->hand_baudrate;
__this->UART->CON0 = BIT(13) | BIT(12) | BIT(10) | BIT(1) | BIT(0);//占用该串口,不被其他模块使用
/* __this->UART->OTCNT = uart_timeout * (UART_OT_CLK / 1000000); */
__this->UART->BAUD = (UART_SRC_CLK / __this->data->hand_baudrate) / 4 - 1;
__this->baudrate = __this->data->hand_baudrate;
gpio_set_pull_down(__this->data->io_port, 0);
gpio_set_pull_up(__this->data->io_port, 1);
gpio_set_die(__this->data->io_port, 1);
gpio_direction_input(__this->data->io_port);
return true;
}
void vEx_mcu_uart_tx_buf(u8 *uart_dma_buf, u32 dma_buf_len)
{
__this->UART->CON0 = BIT(13) | BIT(12) | BIT(10);
gpio_direction_output(__this->data->io_port, 1);
__this->UART->CON1 |= BIT(4);
if (__this->UART == JL_UART0) {
gpio_set_fun_output_port(__this->data->io_port, FO_UART0_TX, 1, 1);
} else if (__this->UART == JL_UART1) {
gpio_set_fun_output_port(__this->data->io_port, FO_UART1_TX, 1, 1);
} else {
gpio_set_fun_output_port(__this->data->io_port, FO_UART2_TX, 1, 1);
}
/* __this->UART->CON0 |= BIT(2); */
__this->UART->CON0 |= BIT(13) | BIT(12) | BIT(10) | BIT(0);
u32 data_addr = (u32)uart_dma_buf;
if (data_addr % 4) {//4byte对齐
ASSERT(0, "%s: unaligned accesses!", __func__);
}
send_busy = 1;
__this->UART->TXADR = data_addr;
__this->UART->TXCNT = dma_buf_len;
//最长等10ms
vEx_mcu_udelay(10);
while (!(__this->UART->CON0 & BIT(15)));
send_busy = 0;
__this->UART->CON0 |= BIT(13);
gpio_direction_input(__this->data->io_port);
}
u32 ulEx_mcu_uart_rx_buf(u8 *uart_dma_buf, u32 dma_buf_len, u32 timeout)
{
u32 ret = 0;
__this->UART->CON0 = BIT(13) | BIT(12) | BIT(10);
gpio_direction_input(__this->data->io_port);
gpio_set_die(__this->data->io_port, 1);
__this->UART->CON1 &= ~BIT(4);
if (__this->UART == JL_UART0) {
gpio_set_fun_input_port(__this->data->io_port, PFI_UART0_RX);
} else if (__this->UART == JL_UART1) {
gpio_set_fun_input_port(__this->data->io_port, PFI_UART1_RX);
} else {
gpio_set_fun_input_port(__this->data->io_port, PFI_UART2_RX);
}
memset((void *)uart_dma_buf, 0, sizeof(uart_dma_buf));
__this->UART->RXSADR = (u32)uart_dma_buf;
__this->UART->RXEADR = (u32)((((u32)uart_dma_buf + dma_buf_len) + 3) / 4 * 4);
__this->UART->RXCNT = dma_buf_len;
__this->UART->CON0 |= BIT(6) ;
__this->UART->CON0 |= BIT(13) | BIT(12) | BIT(1);
//轮询检查是否收到内容
while (timeout--) {
__asm__ volatile("csync");
if (__this->UART->CON0 & (BIT(14))) {
log_debug("CAAAAAAAAAC\n");
ret = dma_buf_len;
break;
}
//1ms
//log_debug("\n%d\n",timeout);
__this->data->delay(1);
}
__this->UART->CON0 |= BIT(12);
printf_buf((u8 *)uart_dma_buf, dma_buf_len);
return ret;
}
#endif
//=======================================================================//
// 公共部分 //
//=======================================================================//
//从机复位部分
static void reset_ex_mcu(void)
{
gpio_set_direction(TCFG_EX_RESET_PORT, 0);
gpio_set_output_value(TCFG_EX_RESET_PORT, 0);
udelay(5000);
gpio_set_output_value(TCFG_EX_RESET_PORT, 1);
}
void vEx_mcu_set_baudrate(u32 baudrate)
{
__this->baudrate = baudrate;
__this->UART->BAUD = (UART_SRC_CLK / __this->baudrate) / 4 - 1;
}
u8 ucEx_mcu_exit(void)
{
#if TCFG_EX_MCU_OS_ENABLE
free(__this->data->ex_mcu_buf);
#endif
//还是关闭串口功能
#if !TCFG_EX_MCU_UART_TO_USE
__this->UART->CON0 = BIT(13) | BIT(12) | BIT(10);
#endif
return true;
}
//防止其他任务设置时钟紊乱串口时钟内容发送
static void clock_critical_enter(void)
{
if (__this->UART == NULL) {
return;
}
//等待数据发完
while (send_busy);
}
static void clock_critical_exit(void)
{
u32 uart_timeout;
if (__this->UART == NULL) {
return;
}
uart_timeout = 20 * 1000000 / __this->baudrate;
/* __this->UART->OTCNT = uart_timeout * (UART_OT_CLK / 1000000); */
__this->UART->BAUD = (UART_SRC_CLK / __this->baudrate) / 4 - 1;
}
CLOCK_CRITICAL_HANDLE_REG(ex_mcu, clock_critical_enter, clock_critical_exit)
u8 ucEx_mcu_uart_app_file_download(const char *file_app, u32 retry, u32 retry_timeout, u32 file_timeout)
{
ex_mcu_enter_flag = 1;
ucEx_mcu_app_file_download(file_app, /*u8 mode,*/ retry, retry_timeout, file_timeout);
//屏蔽串口中断
ex_mcu_enter_flag = 0;
}
void Ex_mcu_uart_test(void)
{
u8 ret = 0;
//注册从机复位接口到底层
reset_ex_mcu_register(reset_ex_mcu);
//多次使用需要多次初始化参数
#if 0
#include "ex_mcu_uart.h"
extern struct ex_mcu_platform_data ex_mcu_data;
ucEx_mcu_init(&ex_mcu_data);
#endif
ret = ucEx_mcu_uart_app_file_download(EX_MCU_APP_FILE_PATH, 50, 50, 50);
}
#endif /* #if TCFG_EX_MCUE_ENABLE */