1.初始化qapi_uart结构体
uart数据结构分析
typedef struct
{
uint32_t baud_Rate; //波特率
qapi_UART_Parity_Mode_e parity_Mode; //奇偶校验方式
qapi_UART_Num_Stop_Bits_e num_Stop_Bits; //数据结束的bit位数
qapi_UART_Bits_Per_Char_e bits_Per_Char; //每个字符的位数
qbool_t enable_Loopback; //回环功能
qbool_t enable_Flow_Ctrl; //流量控制
boolean user_mode_client; //预留驱动程序
qapi_UART_Callback_Fn_t tx_CB_ISR; //tx回调
qapi_UART_Callback_Fn_t rx_CB_ISR; //rx回调
}qapi_UART_Open_Config_t;
其中,qapi_UART_Open_Config_t结构体中,只有几个是我们需要关注的:
波特率、rx回调。其他的直接参考平台默认配置即可
qapi_UART_Open_Config_t open_properties;
qapi_Status_t q_status;
memset(&open_properties, 0, sizeof(open_properties));
open_properties.parity_Mode = QAPI_UART_NO_PARITY_E;
open_properties.num_Stop_Bits= QAPI_UART_1_0_STOP_BITS_E;
open_properties.baud_Rate = 115200;
open_properties.bits_Per_Char= QAPI_UART_8_BITS_PER_CHAR_E;
open_properties.rx_CB_ISR = bt_rx_cb;
open_properties.tx_CB_ISR = bt_tx_cb;
open_properties.enable_Flow_Ctrl = false;
open_properties.enable_Loopback = false;
open_properties.user_mode_client = false;
2.初始化一个结构体,用于存放配置的uart handle
typedef struct UART_Ctx_s
{
uint8_t buffer[BT_RX_BUFFER_SIZE + 128]; /* 串口接收的缓存Buffer */
volatile uint32_t bufferFree; /* 串口接收缓存剩余大小 */
qapi_UART_Handle_t uartHandle; /* 串口打开时的获取到的handle */
qurt_signal_t event; /* 串口事件处理信号 */
uint8_t uart_on_flg; /* 串口开关标志:1--开 0--关 */
} UART_Ctx_t;
3.将这个结构体注册到uat_port中
qapi_UART_Open(&UART_Ctx_D.uartHandle, g_port_id, &open_properties);
其中,g_port_id是平台使用的uart gpio组
4.底层qapi_uart进行uart的实际初始化
qapi_Status_t qapi_UART_Open
(
qapi_UART_Handle_t* handle,
qapi_UART_Port_Id_e id,
qapi_UART_Open_Config_t* config
)
{
...
memsset(uart_h,0,sizeof(uart_handle));
...
uart_get_device_props(id , &device_info)
...
}
qapi_UART_Open的前面一部分api都是判断这个handle以及gpio组是否已经被初始化过了,初始化中最关键的就是
memsset(uart_h,0,sizeof(uart_handle)); 将上面设置的handle赋值给uart_h
我们直接看下面
init_Config.Ctxt = uart_h;
init_Config.enable_dma = device_info.is_enable_dma;
init_Config.uart_type = UART_BAM;
init_Config.uart_irq = 0; // Read from property file. Don't override here.
init_Config.rx_irq = 0; // Read from property file. Don't override here.
init_Config.LineEventNotif = NULL;//todo rajesh
init_Config.TransmitReadyNotif = (DALNotifyFunc)tx_cb_isr;
init_Config.ReceiveReadyNotif = (DALNotifyFunc)rx_cb_isr;
init_Config.CxmMisalignNotif = NULL;
init_Config.CxmMsgNotif = NULL;
init_Config.CxmRatNotif = NULL;
dal_device_handle = DalUart_Init(&init_Config);
对传入的handle、goio_id以及operation进行合法性校验后,放到UartInitConfig类型的init_config对象中进行uart dal注册,指定了对应的rx、rx回调。
初始化Init_config中主要做了以下事情:
static UART_CONTEXT *mu_init(UartInitConfig *init_cfg)
{
...
if ( !get_properties(uart_ctxt) ) { goto error; }
if ( !map_hardware(uart_ctxt) ) { goto error; }
if ( !create_objects(uart_ctxt) ) { goto error; }
...
HALuart_InitObject(uart_hal, hal_type,
uart_ctxt->uart_mapping->virt_addr,
uart_ctxt->uart_mapping->phys_addr);
...
HALuart_GetFIFOPhysAddrs(uart_hal, &dma_config.rx_fifo, &dma_config.tx_fifo);
...
DalUart_Open(dal_device_handle, &open_config );
...
(!(qurt_qapi_callback_configure(uart_h->pTxp->tx_cb_base, // type
(void *)0xDEADCAFE, // dummy obj_ptr
0, // id
(void *)uart_h->pUartConfig->tx_CB_ISR, // test_api1 - a3: app_cb_dispatcher
(void *)pGlobUartTxCb, // test_api1 - a2: app_cb
(void**)&uart_h->pTxp->tx_cb_func,
NULL)))
...
(!(qurt_qapi_callback_configure(uart_h->pRxp->rx_cb_base, // type
(void *)0xDEADCAFE, // dummy obj_ptr
0, // id
(void *)uart_h->pUartConfig->rx_CB_ISR, // test_api1 - a3: app_cb_dispatcher
(void *)pGlobUartRxCb, // test_api1 - a2: app_cb
(void**)&uart_h->pRxp->rx_cb_func,
NULL)))
...
get_properties:从xml文件中获取dal层可配置的属性
map_hardware:映射物理地址到虚拟地址中
create_objects:创建uart对象,为下面初始化hal层的uart对象做准备
HALuart_GetFIFOPhysAddrs:返回dma交互所需要的rx、tx虚拟地址,上面已经绑定了rx、tx回调函数,这里拿到对应的虚拟地址
DalUart_Open:dal层uart初始化,这里很关键,下面会单独进行讲解
qurt_qapi_callback_configure:绑定uart的rx、tx回调
这里重点讲解以下DalUart_Open函数,其他的api基本都是平台与芯片高度绑定的,物理地址、虚拟地址之类的。我们一般不会对其进行修改。但是我们最上面的uart配置初始化基本是在这里进行处理的。
DalUart_Open实际上是调用mu_open(uart_ctxt, open_cfg)进行初始化的,uart_ctxt就是进行dal初始化的dal_device_handle,open_cfg就是Uart_Ctx_t.open_properties,初始化时的配置项。
static boolean mu_open(UART_CONTEXT *uart_ctxt, UartOpenConfig *open_cfg)
{
void *id = uart_ctxt->init_cfg.device_id;
boolean xfer_result;
if ( !valid_char_format(&open_cfg->char_format) || !valid_rts_control(open_cfg->rts_control) )
{
tal_os_log(id, INFO, "mu_open: invalid parameter");
return FALSE;
}
uart_ctxt->rts_control = open_cfg->rts_control;
uart_ctxt->break_notified = FALSE;
uart_ctxt->rx_overruns = 0;
uart_ctxt->rx_cached_status = 0;
uart_ctxt->rx_activated = FALSE;
uart_ctxt->rx_halt = FALSE;
uart_ctxt->tx_halt = FALSE;
uart_ctxt->tx_wait = FALSE;
uart_ctxt->break_halt = FALSE;
if ( !allocate_buffers(uart_ctxt) ) { goto error; }
if ( !open_devices(uart_ctxt) ) { goto error; }
if ( !configure_interrupts(uart_ctxt) ) { goto error; }
if ( !clock_enable(uart_ctxt) ) { goto error; }
if (uart_ctxt->use_dma)
{
if ( !dma_open(uart_ctxt->dma_ctxt) ) { goto error; }
}
configure_gsbi(uart_ctxt);
if ( !gpio_enable(uart_ctxt) ) { goto error; }
if ( !reg_init(uart_ctxt, open_cfg) ) { goto error; }
if ( !register_isr_for_uart(uart_ctxt) ) { goto error; }
uart_ctxt->power_state = POWER_FULL;
xfer_result = rx_transfer_start(uart_ctxt);
if (xfer_result == FALSE)
{
tal_os_log(id, ERROR, "mu_open: failed to start RX transfer");
goto error;
}
set_rts_control(uart_ctxt, uart_ctxt->rts_control);
start_break_detection(uart_ctxt);
return TRUE;
error:
mu_close(uart_ctxt);
return FALSE;
}
valid_char_format:解析配置的奇偶校验位是否支持
valid_rts_control:解析配置的流量控制是否支持
allocate_buffers:配置rx、tx的buffer大小
open_devices:进行中断配置、gpio配置以及时钟配置
configure_interrupts:中断初始化,核心:uart_ctxt->rx_interrupt.irq = uart_ctxt->init_cfg.rx_irq;uart_ctxt->rx_interrupt.gpio = rx_gpio;
这里指定了rx的中断gpio脚
clock_enable:使能时钟
gpio_enable:使能gpio
reg_init:初始化uart寄存器
register_isr_for_uart:注册uart isr中断,高电平触发
rx_transfer_start:rx数据转换
到这里,uart初始化基本就完成了。
初始化结束后,uart是如何进行工作的呢?
还记得上面进行mu_open中初始化的各种参数吗?其中有一个register_isr_for_uart,用于注册uart的中断函数以及指定触发方式。触发中断后,会进入uart_dpc处理函数
static void *uart_dpc(void *context)
{
UART_CONTEXT *uart_ctxt = (UART_CONTEXT *)context;
void *id = uart_ctxt->init_cfg.device_id;
uint32 uart_events;
HALUartObject *uart_hal = &uart_ctxt->uart_hal;
uint32 isr_back,isr;
...
dbg_restore_uart_event(&uart_events, id);
...
if (uart_events & IRQ_RXSTALE) { service_rx_stale (uart_ctxt); }
if (uart_events & IRQ_RXLEV) { service_rx_watermark (uart_ctxt); }
if (uart_events & IRQ_TXLEV) { service_tx_watermark (uart_ctxt); }
if (uart_events & IRQ_TX_READY) { service_tx_ready (uart_ctxt); }
if (uart_events & IRQ_RXBREAK_START) { service_rx_break_start(uart_ctxt); }
if (uart_events & DMA_RX_COMPLETE) { service_rx_dma (uart_ctxt); }
if (uart_events & DMA_TX_COMPLETE) { service_tx_dma (uart_ctxt); }
...
}
在dpc中,通过uart_events去接收uart中断事件,当中断事件为IRQ_RXSTALE,即uart rx事件,调用service_rx_stale,再判断当前uart的rx是否已经接受完整数据,如果接收完整,再通过notify_rxdata_available进入rx_cb_isr进行下一步调用
那么rx_cb_isr与open_properties.rx_CB_ISR = bt_rx_cb;的关系是什么呢?
static void rx_cb_isr(uart_handle *uart_h)
{
cb_info *pRxNode = NULL;
uint8 *pBuf = NULL;
DALResult result = UART_ERROR;
uint32 bytes_read = 0;
uint32 read_size = 0;
uint32 overrun_events = 0;
uint32 cb_idx = 0;
UartStatusType status = (UartStatusType)0;
if(uart_h == NULL)
{
UART_LOG_0( ERROR, "rx_cb_isr:null handle" );
return;
}
qurt_mutex_lock(uart_h->pRxp->pLock);
pRxNode = malloc(sizeof(cb_info));
if(pRxNode == NULL)
{
UART_LOG_0( TRACE, "[%d] pRxNode:memory alloc failed" );
return;
}
memsset(pRxNode,0,sizeof(cb_info));
while(TRUE == PopHeadNode(&uart_h->pRxp->pRxHead, pRxNode))
{
pBuf = (uint8 *)pRxNode->pBuf;
read_size = pRxNode->size;
result = DalUart_Read(uart_h->pDeviceHandle ,pBuf,
read_size,&bytes_read, &overrun_events);
if(result == UART_SUCCESS)
{
UART_BUFFER_LOG_2( pBuf, bytes_read, "[%d] Recived %d bytes:", 0, bytes_read );
UART_LOG_1(ERROR, "Recived %d bytes:", bytes_read );
pRxNode->size = bytes_read;
if(uart_h->pUartConfig->user_mode_client)
{
uart_h->pRxp->rx_cb_func(pRxNode->size, (UINT)pRxNode->pCbData);
cb_idx = uart_h->pRxp->rx_cb_base - TXM_QAPI_BUSES_UART_CB_BASE;
cb_base_array[cb_idx] = CB_BASE_AVAILABLE;
}
else
{
if(uart_h->pUartConfig->rx_CB_ISR != NULL)
{
uart_h->pUartConfig->rx_CB_ISR(pRxNode->size,pRxNode->pCbData);
}
}
result = DalUart_GetStatus(uart_h->pDeviceHandle,&status);
if((result == UART_SUCCESS) && (status & STATUS_RX_BUFFER_EMPTY))
{
break;
}
bytes_read = 0;
}
}
free(pRxNode);
pRxNode = NULL;
qurt_mutex_unlock(uart_h->pRxp->pLock);
}
这里可以看到,触发了rx_cb_isr后,首先会上个锁qurt_mutex_lock,避免正在处理这一条消息时,又再次触发中断导致数据异常
随后进入在while循环内,通过DalUart_Read对uart数据进行读取,判断uart config配置中是否已经设置rx_CB_ISR回调函数,设置了就会将uart读到的数据长度、数据指针传给uart config中的rx_CB_ISR进行数据解析。
并且,rx_cb_isr会一直等待,直到DalUart_GetStatus中判定uart rx buffer此时为空,即rx_CB_ISR已经将数据全部处理完并清空buffer后,才会进行解锁,等待下一个uart中断。
rx_CB_ISR中的需要实现的就是:
对传入的length、data数据进行解析并处理即可。但是由于底层存在锁,所以耗时的操作不建议放置在rx_CB_ISR中执行。