七.面向对象的嵌入式底层开发-UART(C面向对象开发)

内容参考于《抽象接口技术和组件开发规范及其思想》、《面向ametal框架和接口的C编程》

七.面向对象的嵌入式底层开发-UART

Ametal中uart的实现

内容和道理和led很多相识,uart代码比较多少,我们关注的是接口和对象,无关代码可以直接跳过
资源图(这里只针对uart,如果上升到send/receive,那么涉及到更多的是总线、驱动、操作系统)
在这里插入图片描述

1. demo_std_uart_polling.c
#include "ametal.h"
#include "am_uart.h"

static const uint8_t __ch[] = {"STD-UART test in polling mode:\r\n"};

void demo_std_uart_polling_entry (am_uart_handle_t handle)
{
    uint8_t uart1_buf[5];    /* 数据缓冲区 */

    am_uart_poll_send(handle, __ch, sizeof(__ch));

    while (1) {
        /* 接收字符 */
        am_uart_poll_receive(handle, uart1_buf, 1);

        /* 发送刚刚接收的字符 */
        am_uart_poll_send(handle, uart1_buf, 1);
    }
}
2. am_uart.h(uart标准接口)

内容有点多,主要看am_uart_serv_t,其他略过。

#ifndef __AM_UART_H
#define __AM_UART_H

#ifdef __cplusplus
extern "C" {
#endif

#include "am_common.h"
/**
 * \name UART模式定义
 * @{
 */
#define AM_UART_MODE_POLL         1    /**< \brief UART 查询模式 */
#define AM_UART_MODE_INT          2    /**< \brief UART 中断模式 */
/**
 * \name UART通用控制指令
 * @{
 */
#define AM_UART_BAUD_SET          1   /**< \brief 设置波特率                  */
#define AM_UART_BAUD_GET          2   /**< \brief 获取波特率                  */

#define AM_UART_OPTS_SET          3   /**< \brief 设置硬件参数设置            */
#define AM_UART_OPTS_GET          4   /**< \brief 获取硬件参数设置            */

#define AM_UART_MODE_SET          5   /**< \brief 设置模式                    */
#define AM_UART_MODE_GET          6   /**< \brief 获取当前模式                */
#define AM_UART_AVAIL_MODES_GET   7   /**< \brief 获取支持的有效模式          */

#define AM_UART_FLOWMODE_SET      8   /**< \brief 设置流控模式                */
#define AM_UART_FLOWSTAT_RX_SET   9   /**< \brief 设置接收器流控状态          */
#define AM_UART_FLOWSTAT_TX_GET   10  /**< \brief 获取发送器流控状态          */

#define AM_UART_RS485_SET         11  /**< \brief 设置RS485模式(使能 或 禁能) */
#define AM_UART_RS485_GET         12  /**< \brief 获取当前的RS485模式状态     */
/**
 * \name 硬件参数设置选项,设置硬件参数时,可以是多个选项的或值
 * @{
 */
#define AM_UART_CSIZE    0xc   /**< \brief 位3 ~ 位4为数据宽度                */
#define AM_UART_CS5      0x0   /**< \brief 数据宽度为5位                      */
#define AM_UART_CS6      0x4   /**< \brief 数据宽度为6位                      */
#define AM_UART_CS7      0x8   /**< \brief 数据宽度为7位                      */
#define AM_UART_CS8      0xc   /**< \brief 数据宽度为8位                      */

#define AM_UART_STOPB    0x20  /**< \brief 设置停止位为2位,默认为1位         */
#define AM_UART_PARENB   0x40  /**< \brief 使能奇偶校验,默认奇偶校验是关闭的 */
#define AM_UART_PARODD   0x80  /**< \brief 设置校验为奇校验,默认是偶校验     */
/**
 * \name 流控制设置选项
 * @{
 */
#define AM_UART_FLOWCTL_NO    0xa0    /**< \brief 无流控             */
#define AM_UART_FLOWCTL_HW    0xa1    /**< \brief 硬件流控           */
#define AM_UART_FLOWCTL_SW    0xa2    /**< \brief 软件流控           */

#define AM_UART_FLOWSTAT_ON   0xb0    /**< \brief 开流,继续数据传输 */
#define AM_UART_FLOWSTAT_OFF  0xb1    /**< \brief 关流,停止数据传输 */
/**
 * \name 串行设备回调函数类型编码,用于指定注册何种回调函数
 * @{
 */
#define AM_UART_CALLBACK_TXCHAR_GET   0  /**< \brief 获取一个发送字符      */
#define AM_UART_CALLBACK_RXCHAR_PUT   1  /**< \brief 提交一个接收到的字符  */
#define AM_UART_CALLBACK_ERROR        2  /**< \brief 错误回调函数          */
/**
 * \name 错误回调函数的错误码(code)
 * @{
 */
#define AW_UART_ERR_CODE_NONE        (-1)        /**< \brief 无错误          */
#define AW_UART_ERR_CODE_FRAMING      0          /**< \brief 帧错误          */
#define AW_UART_ERR_CODE_PARITY       1          /**< \brief 校验错误        */
#define AW_UART_ERR_CODE_OFLOW        2          /**< \brief over flow 错误  */
#define AW_UART_ERR_CODE_UFLOW        3          /**< \brief under flow 错误 */
#define AW_UART_ERR_CODE_CONNECT      4          /**< \brief 连接错误        */
#define AW_UART_ERR_CODE_DISCONNECT   5          /**< \brief 断开连接错误    */
#define AW_UART_ERR_CODE_NO_CLK       6          /**< \brief 无可用时钟      */
#define AW_UART_ERR_CODE_UNKNWN       7          /**< \brief 未知错误        */
/**
 * \name 回调函数类型定义
 * @{
 */
/**
 * \brief 获取一个待发送字符
 *
 * \param[in]  p_arg  :设置回调函数时指定的自定义参数
 * \param[out] p_char :获取待发送数据的指针
 *
 * \retval -AM_EEMPTY :获取待发送数据失败,无更多数据需要发送
 * \retval  AM_OK     :获取待发送数据成功, p_char 正确装载了待发送的数据
 */
typedef int (*am_uart_txchar_get_t)(void *p_arg, char *p_char);
/**
 * \brief 提交一个接收到的字符
 *
 * \param[in] p_arg  :设置回调函数时指定的自定义参数
 * \param[in] ch     :接收到的数据
 *
 * \retval -AM_EFULL  : 用户处理接收数据失败,没有足够的内存空间
 * \retval  AM_OK     : 用户处理接收数据成功
 */
typedef int (*am_uart_rxchar_put_t)(void *p_arg, char  ch);
/**
 * \brief 错误回调函数
 *
 * \param[in] p_arg  :设置回调函数时指定的自定义参数
 * \param[in] code   :错误代码
 * \param[in] p_data :附件的错误诊断信息(由平台自定义,可能为NULL)
 * \param[in] size   : 错误诊断信息的长度(由平台自定义,可能为0)
 *
 * \return AM_OK
 */
typedef int (*am_uart_err_t)(void *p_arg, int code, void *p_data, int size);
/**
 * \brief UART驱动函数结构体
 */
struct am_uart_drv_funcs {

    /**\brief UART控制函数     */
    int (*pfn_uart_ioctl)(void *p_drv,int request, void *p_arg);

    /**\brief 启动UART发送函数 */
    int (*pfn_uart_tx_startup)(void *p_drv);

    /**\brief 设置串口回调函数 */
    int (*pfn_uart_callback_set)(void  *p_drv,
                                 int    callback_type,
                                 void  *pfn_callback,
                                 void  *p_arg);

    /**\brief 从串口获取一个字符(查询模式) */
    int (*pfn_uart_poll_getchar)(void *p_drv, char *p_inchar);

    /**\brief 输出一个字符(查询模式)       */
    int (*pfn_uart_poll_putchar)(void *p_drv, char outchar);

};

/**
 * \brief UART服务
 */
typedef struct am_uart_serv {

    /** \brief UART驱动函数结构体指针    */
    struct am_uart_drv_funcs *p_funcs;

    /** \brief 用于驱动函数的第一个参数  */
    void                     *p_drv;
} am_uart_serv_t;

/** \brief UART标准服务操作句柄类型定义  */
typedef am_uart_serv_t *am_uart_handle_t;

/**
 * \brief 串口控制函数
 *
 * \param[in] handle  : UART标准服务操作句柄
 * \param[in] request : 控制指令
 *   - AM_UART_BAUD_SET : 设置波特率, p_arg为 uint32_t类型,值为波特率
 *   - AM_UART_BAUD_GET : 获取波特率, p_arg为 uint32_t指针类型
 *   - AM_UART_OPTS_SET :设置硬件参数,p_arg 为 uint32_t类型(#AM_UART_CS8)
 *   - AM_UART_OPTS_GET :获取当前的硬件参数设置,p_arg为 uint32_t指针类型
 *   - AM_UART_MODE_SET : 设置模式, p_arg值为 AM_UART_MODE_POLL或 AM_UART_MODE_INT
 *   - AM_UART_MODE_GET : 获取当前模式, p_arg为 uint32_t指针类型
 *   - AM_UART_AVAIL_MODES_GET : 获取当前可用的模式, p_arg为 uint32_t指针类型
 *   - AM_UART_FLOWMODE_SET    : 设置流控模式, p_arg 为 AM_UART_FLOWCTL_NO
 *                                                       或  AM_UART_FLOWCTL_OFF
 *   - AM_UART_FLOWSTAT_RX_SET : 设置接收器流控状态, p_arg 为AM_UART_FLOWSTAT_ON 
 *                                                       或 AM_UART_FLOWSTAT_OFF
 *   - AM_UART_FLOWSTAT_TX_GET : 获取发送器流控状态, p_arg 为AM_UART_FLOWSTAT_ON 
 *                                                       或 AM_UART_FLOWSTAT_OFF
 *
 *   - AM_UART_RS485_SET : 设置RS485模式,p_arg为bool_t类型,TURE(使能),FALSE(禁能)
 *   - AM_UART_RS485_GET :获取当前的RS485模式状态,参数为 bool_t 指针类型
 *
 * \param[in,out] p_arg : 该指令对应的参数
 *
 * \retval AM_OK       : 控制指令执行成功
 * \retval -AM_EIO     : 执行错误
 * \retval -AM_ENOTSUP : 指令不支持
 */
am_static_inline
int am_uart_ioctl (am_uart_handle_t handle,int request, void *p_arg)
{
    return handle->p_funcs->pfn_uart_ioctl(handle->p_drv,request,p_arg);
}

/**
 * \brief 启动UART中断模式数据传输
 * \param[in] handle : UART标准服务操作句柄
 * \retval AM_OK : 启动成功
 */
am_static_inline
int am_uart_tx_startup (am_uart_handle_t handle)
{
    return handle->p_funcs->pfn_uart_tx_startup(handle->p_drv);
}

/**
 * \brief 设置UART回调函数
 *
 * \param[in] handle         : UART标准服务操作句柄
 * \param[in] callback_type  : 指明设置的何种回调函数
 *            - AM_UART_CALLBACK_GET_TX_CHAR  : 获取一个发送字符函数
 *            - AM_UART_CALLBACK_PUT_RCV_CHAR : 提交一个接收到的字符给应用程序
 *            - AM_UART_CALLBACK_ERROR        : 错误回调函数
 * \param[in] pfn_callback   : 指向回调函数的指针
 * \param[in] p_arg          : 回调函数的用户参数
 *
 * \retval  AM_OK      : 回调函数设置成功
 * \retval -AM_EINVAL  : 设置失败,参数错误
 */
am_static_inline
int am_uart_callback_set (am_uart_handle_t  handle,
                          int               callback_type,
                          void             *pfn_callback,
                          void             *p_arg)
{
    return handle->p_funcs->pfn_uart_callback_set(handle->p_drv,
                                                  callback_type,
                                                  pfn_callback,
                                                  p_arg);
}

/**
 * \brief UART接收一个数据(查询模式)
 *
 * \param[in]  handle   : UART标准服务操作句柄
 * \param[out] p_inchar : 用于获取数据的指针
 *
 * \retval  AM_OK       : 接收数据成功
 * \retval -AM_EAGAIN   : 接收数据未准备就绪,需重试
 */
am_static_inline
int am_uart_poll_getchar (am_uart_handle_t handle, char *p_inchar)
{
    return handle->p_funcs->pfn_uart_poll_getchar(handle->p_drv, p_inchar);
}

/**
 * \brief UART发送一个数据(查询模式)
 *
 * \param[in] handle  : UART标准服务操作句柄
 * \param[in] outchar : 待发送的数据
 *
 * \retval  AM_OK     : 发送数据成功
 * \retval -AM_EAGAIN : 发送未就绪,需重试
 */
am_static_inline
int am_uart_poll_putchar (am_uart_handle_t handle, char outchar)
{
    return handle->p_funcs->pfn_uart_poll_putchar(handle->p_drv, outchar);
}

/**
 * \brief UART数据发送(查询模式)
 *
 * \param[in] handle  : UART标准服务操作句柄
 * \param[in] p_txbuf : 发送数据缓冲区
 * \param[in] nbytes  : 待发送数据的个数
 *
 * \return 成功发送数据的个数
 */
int am_uart_poll_send(am_uart_handle_t  handle,
                      const uint8_t    *p_txbuf,
                      uint32_t          nbytes);


/**
 * \brief UART数据接收(查询模式)
 *
 * \param[in] handle  : UART标准服务操作句柄
 * \param[in] p_rxbuf : 接收数据缓冲区
 * \param[in] nbytes  : 待接收数据的个数
 *
 * \return 成功接收数据的个数
 */
int am_uart_poll_receive(am_uart_handle_t  handle,
                         uint8_t          *p_rxbuf,
                         uint32_t          nbytes);

/**
 * @}
 */

#ifdef __cplusplus
}
#endif

#endif /* __AM_UART_H */

/* end of file */

3. am_uart.c(uart标准接口)
#include "am_uart.h"

/**
 * \brief USART send data(poll mode)
 *
 * \param[in] handle  : The UART handle
 * \param[in] p_txbuf : The transmit buffer
 * \param[in] nbytes  : The number bytes to transmit
 * 
 * \return The number bytes transmit successful
 */
int am_uart_poll_send (am_uart_handle_t  handle,
                       const uint8_t    *p_txbuf,
                       uint32_t          nbytes)
{
    uint32_t len = nbytes; 
    
    while (len) {
        if (am_uart_poll_putchar(handle, *p_txbuf) != AM_OK) {
             continue;
        }
        
        len--;
        p_txbuf++;
    }
    
    return nbytes;
}
                            
/**
 * \brief USART receive data(poll mode)
 *
 * \param[in] p_usart : Pointer to USART register block
 * \param[in] p_rxbuf : The receive buffer
 * \param[in] nbytes  : The number bytes to receive
 * 
 * \return The number bytes received successful
 */
int am_uart_poll_receive (am_uart_handle_t  handle,
                          uint8_t          *p_rxbuf,
                          uint32_t          nbytes)
{
    uint32_t len = nbytes; 
    
    while (len){
        if (am_uart_poll_getchar(handle, (char *)p_rxbuf) != AM_OK) {
             continue;
        }
        
        len--;
        p_rxbuf++;
    }
    
    return nbytes;
}

以上描述了接口的使用、设备的抽象接口内容,下面描述其底层类实现


4. am_zlg_uart.h

具体硬件是zlg217芯片,主要看am_zlg_uart_dev_t。am_zlg_uart是类,而对象却有uart0,uart1,uart2。

#ifndef __AM_ZLG_UART_H
#define __AM_ZLG_UART_H

#ifdef __cplusplus
extern "C" {
#endif

#include "am_uart.h"
#include "hw/amhw_zlg_uart.h"

/**
 * \brief 用户指定的其它中断发生,p_data的类型为uint32_t,值为串口的中断状态,方
 *        便用户判断具体的中断源,size为1。
 */
#define AM_ZLG_UART_ERRCODE_UART_OTHER_INT  3

/**
 * \brief 串口设备信息结构体,该设备信息用于串口初始化
 */
typedef struct am_zlg_uart_devinfo {

    uint32_t uart_reg_base;     /**< \brief 指向UART寄存器块的指针 */

    uint8_t  inum;              /**< \brief 串口中断号 */

    int      clk_num;           /**<  \brief 时钟ID */

    /**
     * \brief 串口配置标志,AMHW_ZLG_UART_DATA_*宏或AMHW_ZLG_UART_PARITY_*宏
     *        或AMHW_ZLG_UART_STOP_*的或值
     *        (如:AMHW_ZLG_UART_DATA_8BIT|AMHW_ZLG_UART_PARITY_NO
     *                                       |AMHW_ZLG_UART_STOP_1BIT)
     */
    uint8_t  cfg_flags;

    uint32_t baud_rate;         /**< \brief 初始化波特率 */

    /**
     * \brief 指定使能的其它中断,AMHW_ZLG_UART_INT_*宏值或多个AMHW_ZLG_UART_INT_*宏的
     *        或值,除了(# AMHW_ZLG_UART_INT_TX_EMPTY_ENABLE),
     *               (# AMHW_ZLG_UART_INT_RX_VAL_ENABLE)这两个中断。
     */
    uint32_t other_int_enable;

    /** \brief RS485 方向控制函数, AM_TRUE: 发送模式, AM_FALSE: 接收模式 */
    void (*pfn_rs485_dir) (am_bool_t is_txmode);

    void (*pfn_plfm_init)(void);   /**< \brief 平台初始化函数 */

    void (*pfn_plfm_deinit)(void); /**< \brief 平台去初始化函数 */

} am_zlg_uart_devinfo_t;

/**
 * \brief 串口设备结构体定义
 */
typedef struct am_zlg_uart_dev {

    am_uart_serv_t  uart_serv; /**< \brief 标准UART服务 */

    /** \brief 指向用户注册的txchar_get函数 */
    int (*pfn_txchar_get)(void *, char *);

    /** \brief 指向用户注册的rxchar_put函数 */
    int (*pfn_rxchar_put)(void *, char);

    /** \brief 指向用户注册的错误回调函数 */
    int (*pfn_err)(void *, int, void *, int);

    void     *txget_arg;                    /**< \brief txchar_get函数参数 */
    void     *rxput_arg;                    /**< \brief rxchar_put函数参数 */
    void     *err_arg;                      /**< \brief 错误回调函数用户参数 */

    uint8_t   channel_mode;                 /**< \brief 串口模式 中断/查询 */
    uint32_t  baud_rate;                    /**< \brief 串口波特率 */
    uint16_t  options;                      /**< \brief 硬件设置选项 */

    uint32_t  other_int_enable;             /**< \brief 指定使能的其它中断 */

    am_bool_t rs485_en;                     /**< \brief 是否使能了 485 模式 */

    const am_zlg_uart_devinfo_t *p_devinfo; /**< \brief 指向设备信息常量的指针 */

} am_zlg_uart_dev_t;

/**
 * \brief 初始化UART,返回UART标准服务操作句柄
 *
 * \param[in] p_dev     : 指向串口设备的指针
 * \param[in] p_devinfo : 指向串口设备信息常量的指针
 *
 * \return UART标准服务操作句柄,值为NULL时表明初始化失败
 */
am_uart_handle_t am_zlg_uart_init(am_zlg_uart_dev_t              *p_dev,
                                     const am_zlg_uart_devinfo_t *p_devinfo);

/**
 * \brief 不使用UART时,解初始化UART,释放相关资源
 *
 * \param[in] p_dev : 指向串口设备的指针
 */
void am_zlg_uart_deinit (am_zlg_uart_dev_t *p_dev);

#ifdef __cplusplus
}
#endif

#endif /* __AM_ZLG_UART_H */

5. am_zlg_uart.c

内容很多,只需要关注static const struct am_uart_drv_funcs __g_uart_drv_funcsam_zlg_uart_init

#include "am_zlg_uart.h"
#include "am_clk.h"
#include "am_int.h"

#define  __UART_CLK_RATE   24000000

/**
 * \brief 串口模式(查询或中断)设置
 */
int __uart_mode_set (am_zlg_uart_dev_t *p_dev, uint32_t new_mode);

/**
 * \brief 串口硬件设置
 */
int __uart_opt_set (am_zlg_uart_dev_t *p_dev, uint32_t opts);

/* ZLG 串口驱动函数声明 */
static int __uart_ioctl (void *p_drv, int, void *);

static int __uart_tx_startup (void *p_drv);

static int __uart_callback_set (void *p_drv,
                                int   callback_type,
                                void *pfn_callback,
                                void *p_arg);

static int __uart_poll_getchar (void *p_drv, char *p_char);

static int __uart_poll_putchar (void *p_drv, char outchar);

#if 0
static int __uart_connect (void *p_drv);
#endif

static void __uart_irq_handler (void *p_arg);

/** \brief 标准层接口函数实现 */
static const struct am_uart_drv_funcs __g_uart_drv_funcs = {
    __uart_ioctl,
    __uart_tx_startup,
    __uart_callback_set,
    __uart_poll_getchar,
    __uart_poll_putchar,
};

/**
 * \brief 设备控制函数
 *
 * 其中包含设置获取波特率,模式设置(中断/查询),获取支持的模式,硬件选项设置等功能。
 */
static int __uart_ioctl (void *p_drv, int request, void *p_arg)
{
    am_zlg_uart_dev_t *p_dev     = (am_zlg_uart_dev_t *)p_drv;
    amhw_zlg_uart_t   *p_hw_uart = (amhw_zlg_uart_t *)p_dev->p_devinfo->uart_reg_base;

    int status = AM_OK;

    switch (request) {

    /* 波特率设置 */
    case AM_UART_BAUD_SET:

        /* 只有在当前传输完成的基础上才允许修改波特率 */
        while (amhw_zlg_uart_status_flag_check(p_hw_uart, AMHW_ZLG_UART_TX_COMPLETE_FALG) == AM_FALSE);

        status = amhw_zlg_uart_baudrate_set(p_hw_uart,
                                               am_clk_rate_get(p_dev->p_devinfo->clk_num),
                                               (uint32_t)p_arg);

        if (status > 0) {
            p_dev->baud_rate = status;
            status = AM_OK;
        } else {
            status = -AM_EIO;
        }
        break;

    /* 波特率获取 */
    case AM_UART_BAUD_GET:
        *(int *)p_arg = p_dev->baud_rate;
        break;

    /* 模式设置 */
    case AM_UART_MODE_SET:
        status = (__uart_mode_set(p_dev, (int)p_arg) == AM_OK)
                 ? AM_OK : -AM_EIO;
        break;

    /* 模式获取 */
    case AM_UART_MODE_GET:
        *(int *)p_arg = p_dev->channel_mode;
        break;

    /* 获取串口可设置的模式 */
    case AM_UART_AVAIL_MODES_GET:
        *(int *)p_arg = AM_UART_MODE_INT | AM_UART_MODE_POLL;
        break;

    /* 串口选项设置 */
    case AM_UART_OPTS_SET:
        status = (__uart_opt_set(p_dev, (int)p_arg) == AM_OK) ? AM_OK : -AM_EIO;
        break;

    /* 串口选项获取 */
    case AM_UART_OPTS_GET:
        *(int *)p_arg = p_dev->options;
        break;

    case AM_UART_RS485_SET:
        if (p_dev->rs485_en != (am_bool_t)(int)p_arg) {
            p_dev->rs485_en = (am_bool_t)(int)p_arg;
        }
        break;

    case AM_UART_RS485_GET:
        *(int *)p_arg = p_dev->rs485_en;
        break;

    default:
        status = -AM_EIO;
        break;
    }

    return (status);
}

/**
 * \brief 启动串口发送(仅限中断模式)
 */
int __uart_tx_startup (void *p_drv)
{
    char data  = 0;

    am_zlg_uart_dev_t *p_dev     = (am_zlg_uart_dev_t *)p_drv;
    amhw_zlg_uart_t   *p_hw_uart = (amhw_zlg_uart_t *)p_dev->p_devinfo->uart_reg_base;

    /* 使能 485 发送控制引脚 */
    if (p_dev->rs485_en && p_dev->p_devinfo->pfn_rs485_dir) {
        p_dev->p_devinfo->pfn_rs485_dir(AM_TRUE);
    }

    /* 等待上一次传输完成 */
    while (amhw_zlg_uart_status_flag_check(p_hw_uart, AMHW_ZLG_UART_TX_COMPLETE_FALG) == AM_FALSE);

    /* 获取发送数据并发送 */
    if ((p_dev->pfn_txchar_get(p_dev->txget_arg, &data)) == AM_OK) {
        amhw_zlg_uart_data_write(p_hw_uart, data);
    }

    /* 使能发送中断 */
    amhw_zlg_uart_int_enable(p_hw_uart, AMHW_ZLG_UART_INT_TX_EMPTY_ENABLE);
    return AM_OK;
}

/**
 * \brief 配置中断服务回调函数
 */
static int __uart_callback_set (void  *p_drv,
                                int    callback_type,
                                void  *pfn_callback,
                                void  *p_arg)
{
    am_zlg_uart_dev_t *p_dev = (am_zlg_uart_dev_t *)p_drv;

    switch (callback_type) {

    /* 设置发送回调函数中的获取发送字符回调函数 */
    case AM_UART_CALLBACK_TXCHAR_GET:
        p_dev->pfn_txchar_get = (am_uart_txchar_get_t)pfn_callback;
        p_dev->txget_arg      = p_arg;
        return (AM_OK);

    /* 设置接收回调函数中的存放接收字符回调函数 */
    case AM_UART_CALLBACK_RXCHAR_PUT:
        p_dev->pfn_rxchar_put = (am_uart_rxchar_put_t)pfn_callback;
        p_dev->rxput_arg      = p_arg;
        return (AM_OK);

    /* 设置串口异常回调函数 */
    case AM_UART_CALLBACK_ERROR:
        p_dev->pfn_err = (am_uart_err_t)pfn_callback;
        p_dev->err_arg = p_arg;
        return (AM_OK);

    default:
        return (-AM_ENOTSUP);
    }
}

/**
 * \brief 轮询模式下发送一个字符
 */
static int __uart_poll_putchar (void *p_drv, char outchar)
{
    am_zlg_uart_dev_t *p_dev     = (am_zlg_uart_dev_t *)p_drv;
    amhw_zlg_uart_t   *p_hw_uart = (amhw_zlg_uart_t *)p_dev->p_devinfo->uart_reg_base;

    /* 发送模块是否空闲, AM_FALSE:忙; TURE: 空闲 */
    if(amhw_zlg_uart_status_flag_check(p_hw_uart, AMHW_ZLG_UART_TX_EMPTY_FLAG) == AM_FALSE) {
        return (-AM_EAGAIN);
    } else {

        if ((p_dev->rs485_en) && (p_dev->p_devinfo->pfn_rs485_dir != NULL)) {

            /* 设置 485 为发送模式 */
            p_dev->p_devinfo->pfn_rs485_dir(AM_TRUE);
        }

        /* 发送一个字符 */
        amhw_zlg_uart_data_write(p_hw_uart, outchar);

        if (p_dev->rs485_en && p_dev->p_devinfo->pfn_rs485_dir) {

            /* 等待发送完成 */
            while (!(p_hw_uart->csr & 0x01));

            p_dev->p_devinfo->pfn_rs485_dir(AM_FALSE);
        }
    }

    return (AM_OK);
}

/**
 * \brief 轮询模式下接收字符
 */
static int __uart_poll_getchar (void *p_drv, char *p_char)
{
    am_zlg_uart_dev_t *p_dev     = (am_zlg_uart_dev_t *)p_drv;
    amhw_zlg_uart_t   *p_hw_uart = (amhw_zlg_uart_t *)p_dev->p_devinfo->uart_reg_base;
    uint8_t           *p_inchar  = (uint8_t *)p_char;

    /* 接收模块是否空闲,AM_FALSE:忙,正在接收; TURE: 已经接收到一个字符 */
    if(amhw_zlg_uart_status_flag_check(p_hw_uart, AMHW_ZLG_UART_RX_VAL_FLAG) == AM_FALSE) {
        return (-AM_EAGAIN);
    } else {

        /* 接收一个字符 */
        *p_inchar = amhw_zlg_uart_data_read(p_hw_uart);
    }

    return (AM_OK);
}

/**
 * \brief 配置串口模式
 */
int __uart_mode_set (am_zlg_uart_dev_t *p_dev, uint32_t new_mode)
{
    amhw_zlg_uart_t *p_hw_uart = (amhw_zlg_uart_t *)p_dev->p_devinfo->uart_reg_base;

    /* 仅支持以下模式 */
    if ((new_mode != AM_UART_MODE_POLL) && (new_mode != AM_UART_MODE_INT)) {
        return (AM_ERROR);
    }

    if (new_mode == AM_UART_MODE_INT) {

        am_int_connect(p_dev->p_devinfo->inum,
                       __uart_irq_handler,
                       (void *)p_dev);
        am_int_enable(p_dev->p_devinfo->inum);

        /* 使能RDRF接收准中断 */
        amhw_zlg_uart_int_enable(p_hw_uart, AMHW_ZLG_UART_INT_RX_VAL_ENABLE);
    } else {

        /* 关闭所有串口中断 */
        amhw_zlg_uart_int_disable(p_hw_uart, AMHW_ZLG_UART_INT_ALL_ENABLE_MASK);
    }

    p_dev->channel_mode = new_mode;

    return (AM_OK);
}

/**
 * \brief 串口选项配置
 */
int __uart_opt_set (am_zlg_uart_dev_t *p_dev, uint32_t options)
{
    amhw_zlg_uart_t *p_hw_uart = (amhw_zlg_uart_t *)p_dev->p_devinfo->uart_reg_base;
    uint8_t          cfg_flags = 0;

    if (p_dev == NULL) {
        return -AM_EINVAL;
    }

    /* 在改变UART寄存器值前 接收发送禁能 */
    amhw_zlg_uart_disable(p_hw_uart);

    /* 配置数据长度 */
    switch (options & AM_UART_CSIZE) {

    case AM_UART_CS5:
        cfg_flags |= AMHW_ZLG_UART_DATA_5BIT;
        break;

    case AM_UART_CS6:
        cfg_flags |= AMHW_ZLG_UART_DATA_6BIT;
        break;

    case AM_UART_CS7:
        cfg_flags |= AMHW_ZLG_UART_DATA_7BIT;
        break;

    case AM_UART_CS8:
        cfg_flags |= AMHW_ZLG_UART_DATA_8BIT;
        break;

    default:
        break;
    }

    /* 配置停止位 */
    if (options & AM_UART_STOPB) {
        cfg_flags &= ~(0x1 << 2);
        cfg_flags |= AMHW_ZLG_UART_STOP_2BIT;
    } else {
        cfg_flags &= ~(0x1 << 2);
        cfg_flags |= AMHW_ZLG_UART_STOP_1BIT;
    }

    /* 配置检验方式 */
    if (options & AM_UART_PARENB) {
        cfg_flags &= ~(0x3 << 0);

        if (options & AM_UART_PARODD) {
            cfg_flags |= AMHW_ZLG_UART_PARITY_ODD;
        } else {
            cfg_flags |= AMHW_ZLG_UART_PARITY_EVEN;
        }
    } else {
        cfg_flags &= ~(0x3 << 0);
        cfg_flags |= AMHW_ZLG_UART_PARITY_NO;
    }

    /* 保存和生效配置 */
    amhw_zlg_uart_stop_bit_sel(p_hw_uart, (cfg_flags & 0x4));
    amhw_zlg_uart_data_length(p_hw_uart, (cfg_flags & 0x30));
    amhw_zlg_uart_parity_bit_sel(p_hw_uart, (cfg_flags & 0x3));

    amhw_zlg_uart_enable(p_hw_uart);

    p_dev->options = options;

    return (AM_OK);
}

/*******************************************************************************
  UART interrupt request handler
*******************************************************************************/

/**
 * \brief 串口接收中断服务
 */
void __uart_irq_rx_handler (am_zlg_uart_dev_t *p_dev)
{
    amhw_zlg_uart_t *p_hw_uart = (amhw_zlg_uart_t *)p_dev->p_devinfo->uart_reg_base;
    char data;

    /* 是否为接收Rx中断 */
    if (amhw_zlg_uart_int_flag_check(p_hw_uart,AMHW_ZLG_UART_INT_RX_VAL_FLAG) == AM_TRUE) {

        amhw_zlg_uart_int_flag_clr(p_hw_uart, AMHW_ZLG_UART_INT_RX_VAL_FLAG_CLR);

        /* 获取新接收数据 */
        data = amhw_zlg_uart_data_read(p_hw_uart);

        /* 存放新接收数据 */
        p_dev->pfn_rxchar_put(p_dev->rxput_arg, data);
    }
}

/**
 * \brief 串口发送中断服务
 */
void __uart_irq_tx_handler (am_zlg_uart_dev_t *p_dev)
{
    amhw_zlg_uart_t *p_hw_uart = (amhw_zlg_uart_t *)p_dev->p_devinfo->uart_reg_base;

    char data;

    if (amhw_zlg_uart_int_flag_check(p_hw_uart,AMHW_ZLG_UART_INT_TX_EMPTY_FLAG) == AM_TRUE) {

        amhw_zlg_uart_int_flag_clr(p_hw_uart, AMHW_ZLG_UART_INT_TX_EMPTY_FLAG_CLR);

        /* 获取发送数据并发送 */
        if ((p_dev->pfn_txchar_get(p_dev->txget_arg, &data)) == AM_OK) {
            amhw_zlg_uart_data_write(p_hw_uart, data);
        } else {

            /* 没有数据传送就关闭发送中断 */
            amhw_zlg_uart_int_disable(p_hw_uart, AMHW_ZLG_UART_INT_TX_EMPTY_ENABLE);

            /* 禁能485发送控制引脚 */
            if ((p_dev->rs485_en) && (p_dev->p_devinfo->pfn_rs485_dir)) {

                /* 设置 485 为接收模式 */
                p_dev->p_devinfo->pfn_rs485_dir(AM_FALSE);
            }
        }
    }
}

/**
 * \brief 串口中断服务函数
 */
void __uart_irq_handler (void *p_arg)
{
    am_zlg_uart_dev_t  *p_dev     = (am_zlg_uart_dev_t *)p_arg;
    amhw_zlg_uart_t    *p_hw_uart = (amhw_zlg_uart_t *)p_dev->p_devinfo->uart_reg_base;

    uint32_t uart_int_stat        = amhw_zlg_uart_int_flag_get(p_hw_uart);

    if (amhw_zlg_uart_int_flag_check(p_hw_uart,AMHW_ZLG_UART_INT_RX_VAL_FLAG) == AM_TRUE) {
         __uart_irq_rx_handler(p_dev);
    } else if (amhw_zlg_uart_int_flag_check(p_hw_uart,AMHW_ZLG_UART_INT_TX_EMPTY_FLAG) == AM_TRUE) {
        __uart_irq_tx_handler(p_dev);
    } else {

    }

    /* 其他中断 */
    if ((p_dev->other_int_enable & uart_int_stat) != 0) {

        uart_int_stat &= p_dev->other_int_enable;

        if (p_dev->pfn_err != NULL) {
            p_dev->pfn_err(p_dev->err_arg,
                           AM_ZLG_UART_ERRCODE_UART_OTHER_INT,
                           (void *)p_hw_uart,
                           1);
        }
    }

}

#if 0
/**
 * \brief UART中断函数连接,仅使用中断模式时需要调用此函数
 */
int __uart_connect (void *p_drv)
{
    am_zlg_uart_dev_t *p_dev = (am_zlg_uart_dev_t *)p_drv;

    /* 关联中断向量号,开启中断 */
    am_int_connect(p_dev->p_devinfo->inum, __uart_irq_handler, (void *)p_dev);
    am_int_enable(p_dev->p_devinfo->inum);
    amhw_zlg_uart_int_enable(p_dev->p_devinfo->uart_reg_base,
                                p_dev->other_int_enable);

    return AM_OK;
}
#endif /* 0 */

/**
 * \brief 默认回调函数
 *
 * \returns AW_ERROR
 */
static int __uart_dummy_callback (void *p_arg, char *p_outchar)
{
    return (AM_ERROR);
}

/**
 * \brief 串口初始化函数
 */
am_uart_handle_t am_zlg_uart_init (am_zlg_uart_dev_t           *p_dev,
                                      const am_zlg_uart_devinfo_t *p_devinfo)
{
    amhw_zlg_uart_t  *p_hw_uart;
    uint32_t          tmp;

    if (p_devinfo == NULL) {
        return NULL;
    }

    /* 获取配置参数 */
    p_hw_uart                = (amhw_zlg_uart_t  *)p_devinfo->uart_reg_base;
    p_dev->p_devinfo         = p_devinfo;
    p_dev->uart_serv.p_funcs = (struct am_uart_drv_funcs *)&__g_uart_drv_funcs;
    p_dev->uart_serv.p_drv   = p_dev;
    p_dev->baud_rate         = p_devinfo->baud_rate;
    p_dev->options           = 0;

    /* 初始化默认回调函数 */
    p_dev->pfn_txchar_get    = (int (*) (void *, char*))__uart_dummy_callback;
    p_dev->txget_arg         = NULL;
    p_dev->pfn_rxchar_put    = (int (*) (void *, char ))__uart_dummy_callback;
    p_dev->rxput_arg         = NULL;
    p_dev->pfn_err           =
                     (int (*) (void *, int, void*, int))__uart_dummy_callback;

    p_dev->err_arg           = NULL;

    p_dev->other_int_enable  = p_devinfo->other_int_enable  &
                               ~(AMHW_ZLG_UART_INT_TX_EMPTY_ENABLE |
                                 AMHW_ZLG_UART_INT_RX_VAL_ENABLE);
    p_dev->rs485_en          = AM_FALSE;

    /* 获取串口数据长度配置选项 */
    tmp = p_devinfo->cfg_flags;
    tmp = (tmp >> 4) & 0x03;

    switch (tmp) {

    case 0:
        p_dev->options |= AM_UART_CS5;
        break;

    case 1:
        p_dev->options |= AM_UART_CS6;
        break;
    case 2:
        p_dev->options |= AM_UART_CS7;
        break;
    case 3:
        p_dev->options |= AM_UART_CS8;
        break;

    default:
        p_dev->options |= AM_UART_CS8;
        break;
    }

    /* 开启UART时钟 */
    am_clk_enable(p_devinfo->clk_num);

    /* 获取串口检验方式配置选项 */
    tmp = p_devinfo->cfg_flags;
    tmp = (tmp >> 0) & 0x03;

    if (tmp == 1) {
        p_dev->options |= AM_UART_PARENB | AM_UART_PARODD;
    } else {
    }

    /* 获取串口停止位配置选项 */
    if (p_devinfo->cfg_flags & (AMHW_ZLG_UART_STOP_2BIT)) {
        p_dev->options |= AM_UART_STOPB;
    } else {

    }

    /* 等待上一次传输完成 */
    while (amhw_zlg_uart_status_flag_check(p_hw_uart, AMHW_ZLG_UART_TX_COMPLETE_FALG) == AM_FALSE);

    __uart_opt_set (p_dev, p_dev->options);

    /* 设置波特率 */
    p_dev->baud_rate = amhw_zlg_uart_baudrate_set(
                                     p_hw_uart,
                                     am_clk_rate_get(p_dev->p_devinfo->clk_num),
                                     p_devinfo->baud_rate);
    /* 默认轮询模式 */
    __uart_mode_set(p_dev, AM_UART_MODE_POLL);

    /* uart使能 */

    amhw_zlg_uart_rx_enable(p_hw_uart,AM_TRUE);
    amhw_zlg_uart_tx_enable(p_hw_uart,AM_TRUE);
    amhw_zlg_uart_enable(p_hw_uart);

    if (p_dev->p_devinfo->pfn_plfm_init) {
        p_dev->p_devinfo->pfn_plfm_init();
    }

    if (p_dev->p_devinfo->pfn_rs485_dir) {

        /* 初始化 485 为接收模式 */
        p_dev->p_devinfo->pfn_rs485_dir(AM_FALSE);
    }

    return &(p_dev->uart_serv);
}

/**
 * \brief 串口去初始化
 */
void am_zlg_uart_deinit (am_zlg_uart_dev_t *p_dev)
{
    amhw_zlg_uart_t *p_hw_uart = (amhw_zlg_uart_t *)p_dev->p_devinfo->uart_reg_base;
    p_dev->uart_serv.p_funcs   = NULL;
    p_dev->uart_serv.p_drv     = NULL;

    if (p_dev->channel_mode == AM_UART_MODE_INT) {

        /* 默认为轮询模式 */
        __uart_mode_set(p_dev, AM_UART_MODE_POLL);
    }

    /* 关闭串口 */
    amhw_zlg_uart_disable(p_hw_uart);

    am_int_disable(p_dev->p_devinfo->inum);

    if (p_dev->p_devinfo->pfn_plfm_deinit) {
        p_dev->p_devinfo->pfn_plfm_deinit();
    }
}

以上描述了底层类实现,下面描述其底层对象实现


6. am_hwconf_zlg217_uart.c

am_hwconf_zlg217_uart.h略

#include "am_gpio.h"
#include "am_zlg_uart.h"
#include "amhw_zlg_uart.h"
#include "am_clk.h"
#include "am_zlg217.h"
#include "amhw_zlg217_gpio.h"
#include "zlg217_periph_map.h"
#include "amhw_zlg217_rcc.h"
#include "zlg217_pin.h"

/** \brief 串口1平台初始化 */
static void __zlg217_plfm_uart1_init (void)
{
    am_gpio_pin_cfg(PIOA_9,  PIOA_9_UART1_TX_REMAP0 | PIOA_9_AF_PP );
    am_gpio_pin_cfg(PIOA_10, PIOA_10_UART1_RX_REMAP0| PIOA_10_INPUT_FLOAT);
}

/** \brief 解除串口1平台初始化 */
static void __zlg217_plfm_uart1_deinit (void)
{
    am_clk_disable(CLK_UART1);

    am_gpio_pin_cfg(PIOA_9, AM_GPIO_INPUT);
    am_gpio_pin_cfg(PIOA_10,AM_GPIO_INPUT);
}

/** \brief 串口1设备信息 */
static const am_zlg_uart_devinfo_t __g_uart1_devinfo = {

    ZLG217_UART1_BASE,            /**< \brief 串口1 */
    INUM_UART1,                   /**< \brief 串口1的中断编号 */
    CLK_UART1,                    /**< \brief 串口1的时钟 */

    AMHW_ZLG_UART_DATA_8BIT |  /**< \brief 8位数据 */
    AMHW_ZLG_UART_PARITY_NO |  /**< \brief 无极性 */
    AMHW_ZLG_UART_STOP_1BIT,   /**< \brief 1个停止位 */

    115200,                       /**< \brief 设置的波特率 */

    0,                            /**< \brief 无其他中断 */

    NULL,                         /**< \brief UART1使用RS485 */
    __zlg217_plfm_uart1_init,     /**< \brief UART1的平台初始化 */
    __zlg217_plfm_uart1_deinit,   /**< \brief UART1的平台去初始化 */
};

/**< \brief 定义串口1 设备 */
static am_zlg_uart_dev_t  __g_uart1_dev;

/** \brief 串口2平台初始化 */
static void __zlg217_plfm_uart2_init (void)
{
    am_gpio_pin_cfg(PIOA_2, PIOA_2_UART2_TX | PIOA_2_AF_PP|PIOA_3_SPEED_2MHz);
    am_gpio_pin_cfg(PIOA_3, PIOA_3_UART2_RX | PIOA_3_INPUT_FLOAT);
}

/** \brief 解除串口2 平台初始化 */
static void __zlg217_plfm_uart2_deinit (void)
{

    /* 关闭UART2时钟 */
    am_clk_disable(CLK_UART2);

    am_gpio_pin_cfg(PIOA_3, AM_GPIO_INPUT);
    am_gpio_pin_cfg(PIOA_2, AM_GPIO_INPUT);
}

/** \brief 串口2 设备信息 */
static const am_zlg_uart_devinfo_t __g_uart2_devinfo = {

    ZLG217_UART2_BASE,              /**< \brief 串口2 */
    INUM_UART2,                     /**< \brief 串口2的中断编号 */
    CLK_UART2,                      /**< \brief 串口2的时钟 */

    AMHW_ZLG_UART_DATA_8BIT |    /**< \brief 8位数据 */
    AMHW_ZLG_UART_PARITY_NO |    /**< \brief 无极性 */
    AMHW_ZLG_UART_STOP_1BIT,     /**< \brief 1个停止位 */

    115200,                         /**< \brief 设置的波特率 */

    0,                              /**< \brief 无其他中断 */

    NULL,                           /**< \brief UART2使用RS485 */
    __zlg217_plfm_uart2_init,       /**< \brief UART2的平台初始化 */
    __zlg217_plfm_uart2_deinit,     /**< \brief UART2的平台去初始化 */
};

/**< \brief 定义串口2设备 */
static am_zlg_uart_dev_t  __g_uart2_dev;

/** \brief 串口3平台初始化 */
static void __zlg217_plfm_uart3_init (void)
{
     am_gpio_pin_cfg(PIOB_10, PIOB_10_UART3_TX_REMAP0 | PIOB_10_AF_PP | PIOB_10_SPEED_10MHz);
     am_gpio_pin_cfg(PIOB_11, PIOB_11_UART3_RX_REMAP0 | PIOB_11_INPUT_FLOAT);
}

/** \brief 解除串口3 平台初始化 */
static void __zlg217_plfm_uart3_deinit (void)
{
    am_clk_disable(CLK_UART3);

    am_gpio_pin_cfg(PIOB_10, AM_GPIO_INPUT);
    am_gpio_pin_cfg(PIOB_11, AM_GPIO_INPUT);
}

/** \brief 串口3 设备信息 */
static const am_zlg_uart_devinfo_t __g_uart3_devinfo = {

    ZLG217_UART3_BASE,              /**< \brief 串口3 */
    INUM_UART3,                     /**< \brief 串口2的中断编号 */
    CLK_UART3,                      /**< \brief 串口2的时钟 */

    AMHW_ZLG_UART_DATA_8BIT |    /**< \brief 8位数据 */
    AMHW_ZLG_UART_PARITY_NO |    /**< \brief 无极性 */
    AMHW_ZLG_UART_STOP_1BIT,     /**< \brief 1个停止位 */

    115200,                         /**< \brief 设置的波特率 */

    0,                              /**< \brief 无其他中断 */

    NULL,                           /**< \brief UART3使用RS485 */
    __zlg217_plfm_uart3_init,       /**< \brief UART3的平台初始化 */
    __zlg217_plfm_uart3_deinit,     /**< \brief UART3的平台去初始化 */
};

/**< \brief 定义串口2设备 */
static am_zlg_uart_dev_t  __g_uart3_dev;

/** \brief UART1实例初始化,获得uart1标准服务句柄 */
am_uart_handle_t am_zlg217_uart1_inst_init (void)
{
    return am_zlg_uart_init(&__g_uart1_dev, &__g_uart1_devinfo);
}

/** \brief UART1实例解初始化 */
void am_zlg217_uart1_inst_deinit (am_uart_handle_t handle)
{
    am_zlg_uart_deinit((am_zlg_uart_dev_t *)handle);
}

/** \brief UART2实例初始化,获得uart2标准服务句柄 */
am_uart_handle_t am_zlg217_uart2_inst_init (void)
{
    return am_zlg_uart_init(&__g_uart2_dev, &__g_uart2_devinfo);
}

/** \brief UART2实例解初始化 */
void am_zlg217_uart2_inst_deinit (am_uart_handle_t handle)
{
    am_zlg_uart_deinit((am_zlg_uart_dev_t *)handle);
}

/** \brief UART3实例初始化,获得uart3标准服务句柄 */
am_uart_handle_t am_zlg217_uart3_inst_init (void)
{
    return am_zlg_uart_init(&__g_uart3_dev, &__g_uart3_devinfo);
}

/** \brief UART3实例解初始化 */
void am_zlg217_uart3_inst_deinit (am_uart_handle_t handle)
{
    am_zlg_uart_deinit((am_zlg_uart_dev_t *)handle);
}

/* end of file */

7. 应用
void demo_zlg217_core_std_uart_polling_entry (void)
{
    AM_DBG_INFO("demo am217_core std uart polling!\r\n");

     /* 等待发送数据完成 */
    am_mdelay(100);

    demo_std_uart_polling_entry(am_zlg217_uart1_inst_init());
}
  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值