程序小白
认证:优质创作者
所在专题目录 查看专题
单片机应用与驱动开发之路:这时的你只需要扣动扳机。
RT-Thread驱动之路:stm32设备驱动开发之uart注册①
RT-Thread驱动之路:stm32设备驱动开发之uart设备创建②
RT-Thread驱动之路:stm32设备驱动开发之uart操作方法③
RT-Thread驱动之路:stm32设备驱动开发之uart中断处理④
RT-Thread驱动之路:stm32设备驱动开发之浅析注册机制⑤
作者动态 更多
电子元器件那些事儿:三极管工作区的判断如此简单①
4天前
RT-Thread驱动之路:stm32设备驱动开发之SPI原理①
1星期前
RT-Thread驱动之路:stm32设备驱动开发之浅析注册机制⑤
2星期前
RT-Thread驱动之路:stm32设备驱动开发之uart中断处理④
2星期前
电子元器件那些事儿:继电器电路驱动设计②
2星期前

RT-Thread驱动之路:stm32设备驱动开发之uart中断处理④


      开篇分割线,我们在上一篇讲过了uart相关的ops函数集,还有个更重要的就是uart中断,发送你可以不用,但是接收什么时候来数据,数据能不能及时的进行处理,这都离不开中断的作用,所以一般应用中中断接收是必选项。

      我们在写uart驱动的时候,就需要考虑如何将中断事件(有接收数据到达)通知给uart设备驱动框架(也就是serial层),怎么发通知呢,当然是调用uart设备驱动框架提供的rt_hw_serial_isr函数,设备框架才能知道中断到底发生了什么事。函数原型如下:

      serial:串口设备句柄,来自于哪个串口设备的中断,对应的句柄就是谁。

      event:中断事件类型。

      接下来看一下stm32——uart设备中断处理的真实操作:

/*uart_isr的主要用途:调用框架层rt_hw_serial_isr,通知上层中断已经发生*/
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中断  发送中断等不是重点,不展开了。
}

      这段代码是uart_isr 的一部分专门处理接收中断触发的数据,作用很简单,如果读数据寄存器不为空,且RXNE为中断使能状态,则调用rt_hw_serial_isr触发读数据操作,关于该函数的响应事件类型如下:

#define RT_SERIAL_EVENT_RX_IND          0x01    /* 接收一个字节数据*/
#define RT_SERIAL_EVENT_TX_DONE         0x02    /* 一个字节数据发送完成   */
#define RT_SERIAL_EVENT_RX_DMADONE      0x03    /* DMA接收完成 */
#define RT_SERIAL_EVENT_TX_DMADONE      0x04    /* DMA发送完成*/

      接下来我们看下框架提供的代码都做了哪些工作?

/* 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;
        }
//.......这部分处理其它的事件响应
}
}

      当触发事件为接收一个字符是,那么就开启读取一个字符,在进行数据存储时防止数据出现异常,关闭硬件中断,写入成功后再次开启终端,再中断关闭时,中断标记位是有效的,也就是说连续来的数据可能已经写入到了DR寄存器中,所以这个时候就可以连续读DR寄存器,直到ch返回-1。这个时候代表这当前已无数据,判断当前回调函数是否为空,不为空则更新缓冲区新存入数据长度(这个过程依旧是关中断执行)。得到正确的数据长度后,调用回调函数读取数据,到这里关于uart设备驱动的全部内容就结束了,当然关于发送中断、DMA中断部分内容并没有深入去讲解,感兴趣的小伙伴可以自己尝试分析分析该部分代码的实现逻辑。

      接下来是我们更感兴趣的serial层数据的处理,筒子们下期再见~!

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 2
收藏 3
关注 135
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧