開篇分割線,我們在上一篇講過了uart相關(guān)的ops函數(shù)集,還有個更重要的就是uart中斷,發(fā)送你可以不用,但是接收什么時候來數(shù)據(jù),數(shù)據(jù)能不能及時的進行處理,這都離不開中斷的作用,所以一般應用中中斷接收是必選項。
我們在寫uart驅(qū)動的時候,就需要考慮如何將中斷事件(有接收數(shù)據(jù)到達)通知給uart設備驅(qū)動框架(也就是serial層),怎么發(fā)通知呢,當然是調(diào)用uart設備驅(qū)動框架提供的rt_hw_serial_isr函數(shù),設備框架才能知道中斷到底發(fā)生了什么事。函數(shù)原型如下:
serial:串口設備句柄,來自于哪個串口設備的中斷,對應的句柄就是誰。
event:中斷事件類型。
接下來看一下stm32——uart設備中斷處理的真實操作:
/*uart_isr的主要用途:調(diào)用框架層rt_hw_serial_isr,通知上層中斷已經(jīng)發(fā)生*/
static void uart_isr(struct rt_serial_device *serial)
{
struct stm32_uart *uart;
#ifdef RT_SERIAL_USING_DMA
rt_size_t recv_total_index, recv_len;
rt_base_t level;
#endif
RT_ASSERT(serial != RT_NULL);
uart = rt_container_of(serial, struct stm32_uart, serial);
/* UART in mode Receiver -------------------------------------------------*/
if ((__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_RXNE) != RESET) &&
(__HAL_UART_GET_IT_SOURCE(&(uart->handle), UART_IT_RXNE) != RESET))
{
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
}
//......這里還有好多處理 例如DMA中斷 發(fā)送中斷等不是重點,不展開了。
}
這段代碼是uart_isr 的一部分專門處理接收中斷觸發(fā)的數(shù)據(jù),作用很簡單,如果讀數(shù)據(jù)寄存器不為空,且RXNE為中斷使能狀態(tài),則調(diào)用rt_hw_serial_isr觸發(fā)讀數(shù)據(jù)操作,關(guān)于該函數(shù)的響應事件類型如下:
#define RT_SERIAL_EVENT_RX_IND 0x01 /* 接收一個字節(jié)數(shù)據(jù)*/
#define RT_SERIAL_EVENT_TX_DONE 0x02 /* 一個字節(jié)數(shù)據(jù)發(fā)送完成 */
#define RT_SERIAL_EVENT_RX_DMADONE 0x03 /* DMA接收完成 */
#define RT_SERIAL_EVENT_TX_DMADONE 0x04 /* DMA發(fā)送完成*/
接下來我們看下框架提供的代碼都做了哪些工作?
/* ISR for serial interrupt */
void rt_hw_serial_isr(struct rt_serial_device *serial, int event)
{
switch (event & 0xff)
{
case RT_SERIAL_EVENT_RX_IND:
{
int ch = -1;
rt_base_t level;
struct rt_serial_rx_fifo* rx_fifo;
/* interrupt mode receive */
rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx;
RT_ASSERT(rx_fifo != RT_NULL);
while (1)
{
ch = serial->ops->getc(serial);
if (ch == -1) break;
/* disable interrupt */
level = rt_hw_interrupt_disable();
rx_fifo->buffer[rx_fifo->put_index] = ch;
rx_fifo->put_index += 1;
if (rx_fifo->put_index >= serial->config.bufsz) rx_fifo->put_index = 0;
/* if the next position is read index, discard this 'read char' */
if (rx_fifo->put_index == rx_fifo->get_index)
{
rx_fifo->get_index += 1;
rx_fifo->is_full = RT_TRUE;
if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0;
_serial_check_buffer_size();
}
/* enable interrupt */
rt_hw_interrupt_enable(level);
}
/* invoke callback */
if (serial->parent.rx_indicate != RT_NULL)
{
rt_size_t rx_length;
/* get rx length */
level = rt_hw_interrupt_disable();
rx_length = (rx_fifo->put_index >= rx_fifo->get_index)? (rx_fifo->put_index - rx_fifo->get_index):
(serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index));
rt_hw_interrupt_enable(level);
if (rx_length)
{
serial->parent.rx_indicate(&serial->parent, rx_length);
}
}
break;
}
//.......這部分處理其它的事件響應
}
}
當觸發(fā)事件為接收一個字符是,那么就開啟讀取一個字符,在進行數(shù)據(jù)存儲時防止數(shù)據(jù)出現(xiàn)異常,關(guān)閉硬件中斷,寫入成功后再次開啟終端,再中斷關(guān)閉時,中斷標記位是有效的,也就是說連續(xù)來的數(shù)據(jù)可能已經(jīng)寫入到了DR寄存器中,所以這個時候就可以連續(xù)讀DR寄存器,直到ch返回-1。這個時候代表這當前已無數(shù)據(jù),判斷當前回調(diào)函數(shù)是否為空,不為空則更新緩沖區(qū)新存入數(shù)據(jù)長度(這個過程依舊是關(guān)中斷執(zhí)行)。得到正確的數(shù)據(jù)長度后,調(diào)用回調(diào)函數(shù)讀取數(shù)據(jù),到這里關(guān)于uart設備驅(qū)動的全部內(nèi)容就結(jié)束了,當然關(guān)于發(fā)送中斷、DMA中斷部分內(nèi)容并沒有深入去講解,感興趣的小伙伴可以自己嘗試分析分析該部分代碼的實現(xiàn)邏輯。
接下來是我們更感興趣的serial層數(shù)據(jù)的處理,筒子們下期再見~!