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);
    }

}
原文地址:https://www.cnblogs.com/ht-beyond/p/5061923.html