GPIO(外部上拉、外部下拉、外部没有上下拉的判断)
外部上拉下拉的意思:
For GPIO-IN pin, we can read its status through function DalTlmm_GpioIn(), but it is not easy tell whether it is pulled or driven externally. This software solution can be used for such purpose. Answer: We will rely on the following logic to judge how GPIO is pulled/driven externally. 1. If we set GPIO to INPUT, INTERNAL PULL_UP, GPIO_IN read high. If we set GPIO INPUT, INTERNAL PULL_DOWN, GPIO_IN read high. Then, we can tell that GPIO is pulled/driven high from outside. 2. If we set GPIO to INPUT, INTERNAL PULL_UP, GPIO_IN read low. If we set GPIO INPUT, INTERNAL PULL_DOWN, GPIO_IN read low. Then, we can tell that GPIO is pulled/driven low from outside. 3. If we set GPIO to INPUT, INTERNAL PULL_UP, GPIO_IN read high. If we set GPIO INPUT, INTERNAL PULL_DOWN, GPIO_IN read low. Then, we can tell that GPIO is not pulled/driven from outside.
怎么判断是否有上拉货下拉:
//Configure internal pull up and Enable GPIO, DET_PIN_A_PU: internal pull up DalTlmm_ConfigGpio( handle, (uint32)DET_PIN_A_PU, DAL_TLMM_GPIO_ENABLE); //Delay 10ms rex_sleep(10); //Read GPIO to value1 DalTlmm_GpioIn(handle, (DALGpioSignalType)DET_PIN_A_PU, &value1); // Configure internal pull down and Enable GPIO, DET_PIN_A_PD: internal pull down DalTlmm_ConfigGpio(handle, (uint32)DET_PIN_A_PD, DAL_TLMM_GPIO_ENABLE); // Delay 10ms rex_sleep(10); // Read GPIO to value2 DalTlmm_GpioIn(handle, (DALGpioSignalType)DET_PIN_A_PD, &value2); // Judge value1 and value2 to know how is this GPIO pulled/driven externally: if((value1==DAL_GPIO_HIGH_VALUE)&&(value2==DAL_GPIO_HIGH_VALUE)) { //GPIO is pulled/driven high externally GPIN_IN_value = GPIO_EXTERNAL_DRIVEN_HIGH; } else if((value1==DAL_GPIO_LOW_VALUE)& &(value2==DAL_GPIO_LOW_VALUE)) { //GPIO is pulled/driven low externally GPIN_IN_value = GPIO_EXTERNAL_DRIVEN_LOW; } else if((value1==DAL_GPIO_HIGH_VALUE)& &(value2==DAL_GPIO_LOW_VALUE)) { //GPIO is not pulled/driven externally GPIN_IN_value = GPIO_EXTERNAL_NO_DRIVEN; }
we will rely on the following logic to judge how GPIO is pulled/driven externally.
1. If we set GPIO to INPUT, INTERNAL PULL_UP, GPIO_IN read high. If we set GPIO INPUT,
INTERNAL PULL_DOWN, GPIO_IN read high. Then, we can tell that GPIO is pulled/driven high from
outside.
2. If we set GPIO to INPUT, INTERNAL PULL_UP, GPIO_IN read low. If we set GPIO INPUT,
INTERNAL PULL_DOWN, GPIO_IN read low. Then, we can tell that GPIO is pulled/driven low from
outside.
3. If we set GPIO to INPUT, INTERNAL PULL_UP, GPIO_IN read high. If we set GPIO INPUT,
INTERNAL PULL_DOWN, GPIO_IN read low. Then, we can tell that GPIO is not pulled/driven from
outside.
使用GPIOs: 要使用GPIO,系统首先要分配一个GPIO,使用gpio_request() 为系统分配一个GPIO,接下来要做的一件事是标示GPIO的方向,通常在使用GPIO建立一个platform_device时(位于单板的setup代码中):
/* set as input or output, returning 0 or negative errno */ int gpio_direction_input(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value)
返回0标示成功,或是一个负的errno错误码。它应该被检查,因为get/set调用没有错误返回,且可能会有错误配置。你通常应该在线程上下文中使用这些调用。
Spinlock-Safe GPIO访问
大多数GPIO控制器可以使用内存读写指令访问。它们不需要休眠,且可以从内部硬件中断处理(非线程)和类似的上下文环境安全完成。
使用下列调用访问这些GPIO,此时gpio_cansleep将总是返回错误
/* GPIO INPUT: return zero or nonzero */ int gpio_get_value(unsigned gpio); /* GPIO OUTPUT */ void gpio_set_value(unsigned gpio, int value);
其中,value是一个布尔型参数,零表示低,非零表示高。当读一个输出管脚的值时,返回的值应该是在管脚上看到的值...这并不总是与指定输出值相匹配的,因为存在开漏信号和输出延迟问题。
可能睡眠的GPIO访问:
一些GPIO控制器必须使用基于消息的总线如I2C和SPI来进行访问。读写这些GPIO的命令需要等待到达发送队列的开始和获取它的响应。这需要休眠,且不能从内部中断处理函数中完成。
对于这种GPIO调用gpio_cansleep接口将返回非零值(需要一个有效的GPIO号码,并已经提前使用gpio_request进行分配)
int gpio_cansleep(unsigned gpio);
为了访问这些GPIO,一个不同的访问函数集被定义
/* GPIO INPUT: return zero or nonzero, might sleep */ int gpio_get_value_cansleep(unsigned gpio); /* GPIO OUTPUT, might sleep */ void gpio_set_value_cansleep(unsigned gpio, int value);
访问这样的gpio需要一个可能睡眠的上下文,例如一个线程级别中断处理程序,并且这些访问函数必须代替那些没有cansleep()后缀的spinlock-safe的函数。
考虑到大多数场景中GPIO在它们被声明后实际已经被正确配置,定义了3各附加的调用:
/* request a single GPIO, with initial configuration specified by * 'flags', identical to gpio_request() wrt other arguments and * return value */ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label); /* request multiple GPIOs in a single call */ int gpio_request_array(struct gpio *array, size_t num); /* release multiple GPIOs in a single call */ void gpio_free_array(struct gpio *array, size_t num);
其中,flags参数当前可以指定为下列属性:
* GPIOF_DIR_IN - 配置方向为输入 * GPIOF_DIR_OUT - 配置方向为输出 * GPIOF_INIT_LOW - 作为输出,设置初始值为低 * GPIOF_INIT_HIGH - 作为输出,设置初始值为高 * GPIOF_OPEN_DRAIN - GPIO管脚是开漏极形式 * GPIOF_OPEN_SOURCE - GPIO管脚是开源极形式 由于GPIOF_INIT_*仅仅当配置为输出时有效,所以有效组合为 * GPIOF_IN - 配置为输入 * GPIOF_OUT_INIT_LOW - 配置为输出,初始为低电平 * GPIOF_OUT_INIT_HIGH - 配置为输入,初始为高电平
当设置flag为GPIOF_OPEN_DRAIN时,它将假设管脚是开漏极方式。这类管脚在输出模式将不会被驱动为1。
这样的管脚需要连接上拉。通过使能此flag,当它在输出模式被要求设置为1时,gpio lib将使得方向为输入以使得管脚变高。输出模式下,管脚输出值0以驱动电平为低。
当设置flag为GPIOF_OPEN_SOURCE,它假设管脚时开源极类型。这种管脚在输出模式不能驱动为0。此种管脚需要下拉。通过使能这个flag,当管脚要求输出1时,gpio lib将使得方向变为输入以使得管脚变低。管脚在输出模式驱动1为高