内容参考于《抽象接口技术和组件开发规范及其思想》、《面向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_funcs 和 am_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());
}