2. M601 GPIO 的使用

1 GPIO 相关的数据结构和 API


本文介绍的数据结构和 API 可以参考 SDK 中 zyf_gpio.h 文件


1.1 GPIO 引脚枚举


typedef enum{
PINNAME_WAKE_IN = 0,
PINNAME_AP_READY,
PINNAME_W_DISABLE,
PINNAME_NET_MODE,
PINNAME_NET_STATUS,
PINNAME_SD_INS_DET,
PINNAME_PCM_IN,
PINNAME_PCM_OUT,
PINNAME_PCM_SYNC,
PINNAME_PCM_CLK,
PINNAME_SDC2_DATA3,
PINNAME_SDC2_DATA2,
PINNAME_SDC2_DATA1,
PINNAME_SDC2_DATA0,
PINNAME_SDC2_CMD,
PINNAME_SPI_CS_N,
PINNAME_SPI_MOSI,
PINNAME_SPI_MISO,
PINNAME_SPI_CLK,
PINNAME_I2C_SCL,
PINNAME_I2C_SDA,
PINNAME_STATUS,
PINNAME_RI,
PINNAME_DCD,
PINNAME_CTS,
PINNAME_RTS,
PINNAME_DTR,
PINNAME_MAX
}Enum_PinName;
这些引脚均可做为普通 GPIO 使用,除此之外,还可以复用为其它功能。用作普通 GPIO 使用的时候,参考本文的 API 介绍进行配置。如果用做复用功能时,请参考对应文档进行配置

1.2 GPIO 配置枚举


Enum_PinDirection 配置的是 GPIO 的方向是输入还是输出的。配置为输出可做控制使用如 LED 等,配置为输入可做检测使用如中断检测等。
typedef enum{
PINDIRECTION_IN = 0,
PINDIRECTION_OUT = 1
}Enum_PinDirection;
当配置 Enum_PinDirection 为 PINDIRECTION_OUT 或 1 时,Enum_PinPullSel则不用关心,我们只需要关心下面的 Enum_PinLevel。配置为低则 GPIO 输出低电平;配置为高则 GPIO 输出高电平。
typedef enum{
PINLEVEL_LOW = 0,
PINLEVEL_HIGH = 1
}Enum_PinLevel;
当配置 Enum_PinDirection 为 PINDIRECTION_IN 或 0 时,Enum_PinLevel 则不用关心,我们只需要关心下面的Enum_PinPullSel。配置为 0 则表示禁用拉动选择;配置为 1 则为下拉输入;配置为 2 则为上拉输入。此时的 GPIO 没有输出控制能力,因为配置的方向是输入。
typedef enum{
PINPULLSEL_DISABLE = 0, // Disable pull selection
PINPULLSEL_PULLDOWN = 1, // Pull-down
PINPULLSEL_PULLUP = 2 // Pull-up
}Enum_PinPullSel;

1.3 GPIO 相关 API


1.3.1 ZYF_GpioInit
  此功能启用指定引脚的 GPIO 功能,并初始化配置,包括方向,电平和拉动选择
· 函数原型
int32_t ZYF_GpioInit(Enum_PinName pinName,
  Enum_PinDirection dir,
  Enum_PinLevel level,
  Enum_PinPullSel pullSel
);

· 参数
pinName:参考 1.1 GPIO 引脚枚举
dir:参考 1.2 GPIO 配置枚举
level:参考 1.2 GPIO 配置枚举
pullSel:参考 1.2 GPIO 配置枚举
· 返回值
ZYF_RET_OK,此函数成功
ZYF_RET_ERR_NOSUPPORTPIN,输入 GPIO 无效
ZYF_RET_ERR_PINALREADYSUBCRIBE,在其他地方正在使用 GPIO。 例如,此 GPIO一直用作 EINT


1.3.2 ZYF_GpioSetLevel
  此函数用来设置指定 GPIO 的电平高低
· 函数原型
int32_t ZYF_GpioSetLevel(Enum_PinName pinName, Enum_PinLevel level);
· 参数
pinName:参考 1.1 GPIO 引脚枚举
level:参考 1.2 GPIO 配置枚举
· 返回值
ZYF_RET_OK,此函数成功
ZYF_RET_ERR_NOSUPPORTPIN,输入 GPIO 无效
ZYF_RET_ERR_NORIGHTOPERATE,无法操作,可能是 GPIO 未初始化
ZYF_RET_ERR_NOGPIOMODE,输入的 GPIO 不是 GPIO 模式


1.3.3 ZYF_GpioGetLevel
此函数用来获取指定 GPIO 的电平状态。
· 函数原型
int32_t ZYF_GpioGetLevel(Enum_PinName pinName);
· 参数
pinName:参考 1.1 GPIO 引脚枚举

· 返回值

指定的 GPIO 的电平值,即非负整数
ZYF_RET_ERR_NOSUPPORTPIN,表示输入的 GPIO 无效

1.3.4 ZYF_GpioSetDirection
此函数用来设置指定 GPIO 的方向
· 函数原型
int32_t ZYF_GpioSetDirection(Enum_PinName pinName, Enum_PinDirection dir);
· 参数
pinName:参考 1.1 GPIO 引脚枚举
dir:参考 1.2 GPIO 配置枚举
· 返回值
ZYF_RET_OK 表示此功能成功。
ZYF_RET_ERR_NOSUPPORTPIN,输入 GPIO 无效。
ZYF_RET_ERR_NORIGHTOPERATE,无法操作,可能是 GPIO 未初始化
ZYF_RET_ERR_NOGPIOMODE,输入的 GPIO 不是 GPIO 模式

扫描二维码关注公众号,回复: 11823243 查看本文章

1.3.5 ZYF_GpioGetDirection
此函数用来获取指定 GPIO 的方向
· 函数原型
int32_t ZYF_GpioGetDirection(Enum_PinName pinName);
· 参数
pinName:参考 1.1 GPIO 引脚枚举
· 返回值
指定 GPIO 的方向,即非负整数
* ZYF_RET_ERR_NOSUPPORTPIN,输入 GPIO 无效。
* ZYF_RET_ERR_NORIGHTOPERATE,无法操作,可能是 GPIO 未初始化
* ZYF_RET_ERR_NOGPIOMODE,输入的 GPIO 不是 GPIO 模式

1.3.6 ZYF_GpioSetPullSelection
此函数用来设置指定 GPIO 的拉动选择
· 函数原型
int32_t ZYF_GpioSetPullSelection(Enum_PinName pinName, Enum_PinPullSel
pullSel);
· 参数
pinName:参考 1.1 GPIO 引脚枚举
pullSel:参考 1.2 GPIO 配置枚举
· 返回值
ZYF_RET_OK 表示此功能成功。
ZYF_RET_ERR_NOSUPPORTPIN,输入 GPIO 无效。
ZYF_RET_ERR_NORIGHTOPERATE,无法操作,可能是 GPIO 未初始化
ZYF_RET_ERR_NOGPIOMODE,输入的 GPIO 不是 GPIO 模式

1.3.7 ZYF_GpioGetPullSelection
此函数用来获取指定 GPIO 的拉动状态
· 函数原型
int32_t ZYF_GpioGetPullSelection(Enum_PinName pinName);
· 参数
pinName:参考 1.1 GPIO 引脚枚举
· 返回值
这是非负整数的拉取选择。
如果成功,返回一个 Enum_PinPullSel 值。否则返回
ZYF_RET_ERR_NOSUPPORTPIN,输入 GPIO 无效。
ZYF_RET_ERR_NORIGHTOPERATE,无法操作,可能是 GPIO 未初始化
ZYF_RET_ERR_NOGPIOMODE,输入的 GPIO 不是 GPIO 模式

1.3.8 ZYF_GpioUninit
此函数用来释放指定的 GPIO,释放后,GPIO 可做其它目的

· 函数原型
int32_t ZYF_GpioUninit(Enum_PinName pinName);
· 参数
pinName:参考 1.1 GPIO 引脚枚举
· 返回值
ZYF_RET_OK,此函数成功。
ZYF_RET_ERR_NOSUPPORTPIN,输入 GPIO 无效。
ZYF_RET_ERR_BUSSUBBUSY,未用作 GPIO 的 GPIO,由 IIC 或 SPI 使用,此功能无法释放

2 GPIO 例程介绍

本章节主要介绍如何在 SDK 中使用 example_gpio.c 单独测试 GPIO 功能。
编译方法:.\examples\build\对应的.bat 文件双击执行或打开就可以编译。
生成文件:.\out\对应目录\hex\M601_example_**.pac

使用 ZYF_GpioInit()初始化需要使用到的 GPIO,配置为输出后,可使用ZYF_GpioGetLevel()获取当前电平状态,使用ZYF_GpioSetLevel()设置电平。


#include "zyf_trace.h"
#include "zyf_gpio.h"
#include "zyf_app.h"
#include "zyf_uart.h"
#include "zyf_thread.h"


//fixme:
//rw err: PINNAME_41_I2C_SCL

static Enum_PinName gpiopin[PINNAME_MAX];

static Uart_Param_t g_uart1param;

void UartWriteCallBack(void* Param) // general com
{
    Uart_Param_t *uartparam = (Uart_Param_t *)Param; 
    if(Param == NULL)
    {
        return;
    }    

    ZYF_UartWrite(uartparam->port,(uint8_t *)"UartWrite succeed\r\n",strlen("UartWrite succeed\r\n"));
    ZYF_UartWriteCallbackSwitch(uartparam->port,false);

}

void UartReadCallBack(void* Param) // 
{
    uint32_t recvlen = 0;
    Uart_Param_t *uartparam = (Uart_Param_t *)Param; 

    ZYF_LOG("Uart%d recv",uartparam->port);

    while(ZYF_UartRead(uartparam->port, &(uartparam->uartbuf[recvlen]), 1))
    {
        ZYF_LOG("recv :%02x",uartparam->uartbuf[recvlen]);
        recvlen++;
    }
    ZYF_UartWrite(uartparam->port,uartparam->uartbuf,recvlen);
    ZYF_UartWriteCallbackSwitch(uartparam->port,true);
}


static void AppUartInit(void)
{
    int32_t ret;
    g_uart1param.port = DEBUG_PORT;
    ZYF_UartRegister(g_uart1param.port, UartReadCallBack,&g_uart1param);
    ZYF_UartWriteCbRegister(g_uart1param.port,UartWriteCallBack,&g_uart1param);
    ZYF_UartOpen(g_uart1param.port, 115200, ZYF_FC_NONE);

    ZYF_LOG("AppUartInit");
    return;
}

void ZYF_GpioTest(void)
{
    int i;

    for (i = 0; i < PINNAME_MAX; i ++) {
        ZYF_GpioInit((Enum_PinName)i, PINDIRECTION_OUT, PINLEVEL_LOW, PINPULLSEL_PULLUP);
        ZYF_ThreadSleep(10);
    }

    uint8_t level;
    for (i = 0; i < PINNAME_MAX; i ++) {
        level = ZYF_GpioGetLevel(i);
        ZYF_LOG("read before GPIO:%d => %d", i, level);
        ZYF_ThreadSleep(200);
        ZYF_GpioSetLevel(i, !level);
        ZYF_LOG("write GPIO:%d => %d", i, !level);
        ZYF_ThreadSleep(200);
        level = ZYF_GpioGetLevel(i);
        ZYF_LOG("read after GPIO:%d => %d", i, level);
        ZYF_ThreadSleep(200);
    }

    ZYF_ThreadSleep(1000);
    for (i = 0; i < PINNAME_MAX; i ++) {
        ZYF_GpioUninit(i);
    }
}


void TimeThread_Example(void * Param)
{
    ZYF_MsgQ_t *ptMsg;
    ZYF_AppMsg_t tMsg;
    int iRet = -1;
    ptMsg = ZYF_MsgQCreate(10, sizeof(ZYF_AppMsg_t));
    ZYF_LOG("thread enter!");

    ZYF_GpioTest();
    
    while (1) {
        ZYF_LOG("in while.");
        iRet = ZYF_MsgQGet(ptMsg, (void *)&tMsg);
        if (iRet < 0) {
            ZYF_LOG("Failed to get msg");
            ZYF_ThreadSleep(1000);
        }
    }

}

static void prvInvokeGlobalCtors(void)
{
    extern void (*__init_array_start[])();
    extern void (*__init_array_end[])();

    size_t count = __init_array_end - __init_array_start;
    for (size_t i = 0; i < count; ++i)
        __init_array_start[i]();
}


int appimg_enter(void *param)
{
    AppUartInit();
    ZYF_LOG("application image enter, param 0x%x", param);

    prvInvokeGlobalCtors();

    ZYF_ThreadCreate("UartThread_Example", TimeThread_Example, NULL, ZYF_PRIORITY_HIGH, 10*1024);
    return 0;
}

void appimg_exit(void)
{
    OSI_LOGI(0, "application image exit");
}



猜你喜欢

转载自blog.csdn.net/w_hizyf_m/article/details/107082544