• RT-Thread Mini2440串口驱动


    参照模板自己写了一遍,期间出现很多问题。比如定义全局uart0设备指针后未初始化,导致RT_ASSERT(device != RT_NULL)执行,使设备注册时死机。

    初始化函数没写对,也导致了程序崩溃。

    // uart.h
    // 2015.12.18 by Huangtao
    
    #ifndef __UART_H__
    #define __UART_H__
    
    #include <rtthread.h>
    #include <rthw.h>
    #include <rtthread.h>
    #include <s3c24x0.h>
    
    #define RT_SERIAL_EVENT_RX_IND          0x01    /* Rx indication */
    #define RT_SERIAL_EVENT_TX_DONE         0x02    /* Tx complete   */
    #define RT_SERIAL_EVENT_RX_DMADONE      0x03    /* Rx DMA transfer done */
    #define RT_SERIAL_EVENT_TX_DMADONE      0x04    /* Tx DMA transfer done */
    #define RT_SERIAL_EVENT_RX_TIMEOUT      0x05    /* Rx timeout    */
    
    #define UART_RX_BUFFER_SIZE 64
    
    typedef struct uartport
    {
        volatile rt_uint32_t ulcon;
        volatile rt_uint32_t ucon;
        volatile rt_uint32_t ufcon;
        volatile rt_uint32_t umcon;
        volatile rt_uint32_t ustat;
        volatile rt_uint32_t urxb;
        volatile rt_uint32_t ufstat;
        volatile rt_uint32_t umstat;
        volatile rt_uint32_t utxh;    
        volatile rt_uint32_t urxh;    
        volatile rt_uint32_t ubrd;
    }uartport;
    
    // 中断接收时的ringbuffer缓冲区定义
    struct uart_int_rx
    {
        rt_uint8_t rx_buffer[UART_RX_BUFFER_SIZE];
        rt_uint32_t read_index, save_index;
    };
    
    // 串口设备
    struct uart_device
    {
        uartport* uart_device;
        struct uart_int_rx* int_rx;
    };
    
    extern rt_err_t rt_hw_uart_register(rt_device_t device, const char* name, 
        rt_uint32_t flag, struct uart_device *uart);
    
    extern void rt_hw_uart_isr(rt_device_t device);
    
    extern void rt_hw_uart_init(void);
    
    
    #endif
    // uart.c
    // uart驱动
    // 2015.12.18 by Huangtao
    
    #include "uart.h"
    
    #define baudrate 115200 
    
    extern rt_uint32_t PCLK;
    
    // 设置好uart0的实际物理地址
    #define MYUART0   ((struct uartport *)&U0BASE)
    struct uart_int_rx uart0_int_rx;
    struct uart_device myUart0 =
    {
        MYUART0,
        &uart0_int_rx
    };
    // 全局uart0设备
    struct rt_device myuart0_dev;
    rt_device_t myUart0_device = &myuart0_dev;
    
    
    // 初始化
    static rt_err_t uart_init(rt_device_t dev)
    {
        struct uart_device* uart;
        // 获得真实的UART设备对象    
        uart = (struct uart_device*)dev->user_data;
    
        // 判断设备是否已经激活了
        if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED))
        {
            // 如果是中断接收模式,初始化接收的缓冲区
            if (dev->flag & RT_DEVICE_FLAG_INT_RX)
            {
                rt_memset(uart->int_rx->rx_buffer, 0,
                    sizeof(uart->int_rx->rx_buffer));
                uart->int_rx->read_index = 0;
                uart->int_rx->save_index = 0;
            }
    
            // 设置设备为激活状态
            dev->flag |= RT_DEVICE_FLAG_ACTIVATED;
        }
    
        return RT_EOK;
    }
    
    // 打开设备
    static rt_err_t uart_open(rt_device_t dev, rt_uint16_t oflag)
    {
        RT_ASSERT(dev != RT_NULL);
        
        return RT_EOK;
    }
    
    // 关闭设备
    static rt_err_t uart_close(rt_device_t dev)
    {
        RT_ASSERT(device != RT_NULL);
       
        return RT_EOK;
    }
    
    // 从设备中读取数据
    static rt_size_t uart_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
    {
        rt_base_t level;
        rt_uint8_t* ptr;
        struct uart_device* uart;
        struct uart_int_rx* int_rx;
    
        ptr = buffer;
        uart = (struct uart_device*)dev->user_data;
        int_rx = uart->int_rx;
    
        if (ptr == RT_NULL)
        {
            return RT_ENOMEM;
        }
        if (dev->flag & RT_DEVICE_FLAG_INT_RX)
        {
            // 中断模式接收,中断模式接收在中断服务例程中已预先收取到缓冲区中,
            // 所以这里只需要从缓冲区中复制出数据
            while (size)
            {
                level = rt_hw_interrupt_disable();
    
                if (int_rx->read_index != int_rx->save_index)
                {
                    *ptr++ = int_rx->rx_buffer[int_rx->read_index];
                    size--;
    
                    int_rx->read_index ++;
                    if (int_rx->read_index >= UART_RX_BUFFER_SIZE)
                        int_rx->read_index = 0;
                    rt_hw_interrupt_enable(level);
                }
                else
                {
                    rt_hw_interrupt_enable(level);
                    break;
                }
            }
        }
        else
        {
            // 轮询模式,直接从串口设备中读取数据
            while ((rt_uint32_t)ptr - (rt_uint32_t)buffer < size)
            {
                while (uart->uart_device->ustat & RT_SERIAL_EVENT_RX_IND)
                {
                    *ptr = uart->uart_device->urxh & 0xff;
                    ptr ++;
                }
            }
            
        }
    
        // 返回读取到的字节数
        return (rt_uint32_t)ptr - (rt_uint32_t)buffer;
    }
    
    // 向设备中写入数据
    static rt_size_t uart_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
    {
        rt_uint8_t* ptr;
        struct uart_device* uart;
    
        ptr = (rt_uint8_t*)buffer;
        uart = (struct uart_device*)dev->user_data;
    
        if (ptr == RT_NULL)
        {
            return RT_ENOMEM;
        }
        if ((dev->flag & RT_DEVICE_FLAG_INT_TX))
        {
            
        }
        else
        {
            // 直接写入
            while (size)
            {
                if (*ptr == '
    ' && (dev->flag & RT_DEVICE_FLAG_STREAM))
                {
                    while (!(uart->uart_device->ustat & RT_SERIAL_EVENT_TX_DONE));
                    uart->uart_device->utxh = '
    ';
                }
                //wait Tx empty
                while(!(uart->uart_device->ustat & RT_SERIAL_EVENT_TX_DONE));
                uart->uart_device->utxh = (*ptr & 0xFF);
    
                ++ptr;
                --size;
            }
        
        }
    
        // 返回写入成功的字节数
        return (rt_uint32_t)ptr - (rt_uint32_t)buffer;
    }
    
    // 设备控制操作
    // 还未实现
    static rt_err_t uart_control(rt_device_t dev, rt_uint8_t cmd, void *args)
    {
        RT_ASSERT(dev != RT_NULL);
    
        switch (cmd)
        {
        case RT_DEVICE_CTRL_SUSPEND:
            // 挂起设备
            dev->flag |= RT_DEVICE_FLAG_SUSPENDED;
       
            break;
        
        case RT_DEVICE_CTRL_RESUME:
            // 唤醒设备
            dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED;
    
            break;
        }
    
        return RT_EOK;
    }
    
    // 向系统中注册串口设备
    rt_err_t rt_hw_uart_register(rt_device_t device, const char* name, rt_uint32_t flag, struct uart_device *uart)
    {
        RT_ASSERT(device != RT_NULL);
    
        device->type        = RT_Device_Class_Char;
        device->rx_indicate = RT_NULL;
        device->tx_complete = RT_NULL;
    
        // 设置设备驱动公共接口函数
        device->init        = uart_init;
        device->open        = uart_open;
        device->close       = uart_close;
        device->read        = uart_read;
        device->write       = uart_write;
        device->control     = uart_control;
        device->user_data   = uart;
    
        // 注册设备
        rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | flag);
        
        return RT_EOK;
    }
    
    // ISR for serial interrupt
    void rt_hw_uart_isr(rt_device_t device)
    {
        rt_base_t level;
        struct uart_device* uart;
        struct uart_int_rx* int_rx;
            
        uart = (struct uart_device*)device->user_data;
        int_rx = uart->int_rx;
    
        RT_ASSERT(device->flag & RT_DEVICE_FLAG_INT_RX);
    
        while (uart->uart_device->ustat & RT_SERIAL_EVENT_RX_IND)
        {
            level = rt_hw_interrupt_disable();
                    
            int_rx->rx_buffer[int_rx->save_index] = (uart->uart_device->urxh & 0xff);
            int_rx->save_index ++;
    
            if(int_rx->save_index >= UART_RX_BUFFER_SIZE)
                int_rx->save_index = 0;
    
            // if the next position is read index, discard this 'read char'
            if(int_rx->save_index == int_rx->read_index)
            {
                int_rx->read_index ++;
                if(int_rx->read_index >= UART_RX_BUFFER_SIZE)
                    int_rx->read_index = 0;
            }
            rt_hw_interrupt_enable(level);
        }
        // 接收回调函数
        if(device->rx_indicate != RT_NULL)
        {
            rt_size_t rx_length;
            level = rt_hw_interrupt_disable();
            // get rx length
            rx_length = int_rx->read_index > int_rx->save_index ?
                UART_RX_BUFFER_SIZE - int_rx->read_index + int_rx->save_index :
                int_rx->save_index - int_rx->read_index;
            rt_hw_interrupt_enable(level);
    
            device->rx_indicate(device, rx_length);
        }
    }
    
    // This function will handle serial (参考board.c)
    static void rt_uart_handler(int vector, int event)
    {
        INTSUBMSK |= (BIT_SUB_RXD0);
    
        rt_hw_uart_isr(myUart0_device);
    
        SUBSRCPND |= BIT_SUB_RXD0;
    
        // Unmask sub interrupt (RXD0) 
        INTSUBMSK  &=~(BIT_SUB_RXD0);
    }
    
    void rt_hw_uart_init(void)
    {
        // TX0 GPH2
        // RX0 GPH3
    
        int i;
        // UART0 port configure 
        GPHCON |= 0xAA;
        // PULLUP is disable 
        GPHUP |= 0xF;
    
        // uart FIFO控制寄存器 Disable[0]=0 
        myUart0.uart_device->ufcon = 0x0;
        // uart 模式控制寄存器
        myUart0.uart_device->umcon = 0x0;
        // uart line控制寄存器  8 bit, 1 stop
        myUart0.uart_device->ulcon = 0x3;
    
        // uart控制寄存器
        // 中断或轮询模式发送[3:2]=01,中断或轮询模式接收[1:0]=01
        myUart0.uart_device->ucon = 0x245;
    
        // Set uart0 bps 
        myUart0.uart_device->ubrd = (rt_int32_t)(PCLK / (baudrate * 16)) - 1;
        // output PCLK to UART0/1, PWMTIMER 
        CLKCON |= 0x0D00;
    
        for (i = 0; i < 100; i++);
    
        // install uart0 isr 
        INTSUBMSK &= ~(BIT_SUB_RXD0);
    
        rt_hw_interrupt_install(INTUART0, rt_uart_handler, RT_NULL, "UART0");
        rt_hw_interrupt_umask(INTUART0);
    }

    使用时:

    在rt_application_init(void)函数中注册和初始化:

    rt_hw_uart_register(myUart0_device, "myUart0",
            RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM,
            &myUart0);
    rt_hw_uart_init();

    然后在自己的线程中使用,比如:

    // lcd_td35 测试
    void rt_lcd_thread_entry(void *parameter)
    {
        struct RTC_Date getDate;
        unsigned char rtcBuffer[20];
        unsigned char rx[50] = {''};
        unsigned char *rxBuffer = &rx[0];
    
        Lcd_TD35_Init();
    
        myUart0_device = rt_device_find("myUart0");
        if (myUart0_device != RT_NULL)
        {
            // 初始化设备
            rt_device_init(myUart0_device);
            // 打开设备
            rt_device_open(myUart0_device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX |        
                RT_DEVICE_FLAG_STREAM);
        }
    
        rt_device_write(myUart0_device, 0, "Hello World !", 15);
    
        while(1)
        {    
            Lcd_ClearScr(0);
    
            RTC_Time_Get(&getDate,rtcBuffer);
            Draw_String(0, 0, 200, 100, 0xf800, 12, 1, rtcBuffer);  
            Draw_String(150, 0, 200, 100, 0xf800, 12, 1, "by Huangtao"); 
    
            rt_device_read(myUart0_device, 0, rxBuffer, 10);
            Draw_String(0, 200, 200, 100, 0xf800, 12, 1, rxBuffer);
            rt_device_write(myUart0_device, 0, rxBuffer, 10);
    
            rt_thread_delay(10);
        }
    
    }
  • 相关阅读:
    loj #6201. 「YNOI2016」掉进兔子洞
    poj 3683 Priest John's Busiest Day
    hdu 1814 Peaceful Commission
    poj 3207 Ikki's Story IV
    loj #2305. 「NOI2017」游戏
    uoj #111. 【APIO2015】Jakarta Skyscrapers
    洛谷P1550 [USACO08OCT]打井Watering Hole
    uoj #110. 【APIO2015】Bali Sculptures
    loj #2116. 「HNOI2015」开店
    codevs 3044 矩形面积求并
  • 原文地址:https://www.cnblogs.com/ht-beyond/p/5061923.html
Copyright © 2020-2023  润新知