木子剑
生命不熄,学习不止!

为了先了解contiki NG的文件结构,先上一张图:

共有6大文件:

OS内核心的:--------------->  gpio-hal.h;  gpio-hal.c      这是OS作者提供的

cc2358驱动库的:--------->  gpio.h;  gpio.c                   这是芯片厂家提供的

用户要实现的:------------->  gpio-hal-arch.h;   gpio-hal-arch.c         这是你要编写的

 

因为CONTIKI NG和CONTIKI 3.0有着兼容的设计关系,写了一堆新版\旧版本代码信息共存,看着就有点点乱。还有就是h头文件里面,多数是完整功能的宏函数(linux特性),

用惯了类似STM32库的人员,肯定是1W个不习惯,用上一段时间后,会慢慢适应过来。

 

其实我们只要,熟读和理解一个 或二个OS/DEV驱动的实现原理,就可以依此类推,快速NG上手升级我们应用能力!!就目前开始,我还在阅读

OS与CC2538的GPIO操作方法,希望能领悟其中的巧门!!

 

时间:2020-09-20

看了几天,发现gpio-hal-arch.h和gpio-hal.h还是蛮复杂的,所以我还是先搞定标准库的 gpio.h吧(是NG自带的  不是TI官网下载的)

首先CONTIKI NG提供好了,下面这些宏功能,我们可以直接用它对寄存器操作,只要有官方的寄存器数据就行了,

/**
 * \addtogroup cc2538
 * @{
 *
 * \defgroup cc2538-reg cc2538 Register Manipulation
 *
 * Macros for hardware access, both direct and via the bit-band region.
 * @{
 *
 * \file
 * Header file with register manipulation macro definitions
 */
#ifndef REG_H_
#define REG_H_

#define REG(x)         (*((volatile unsigned long *)(x)))
#define REG_H(x)       (*((volatile unsigned short *)(x)))
#define REG_B(x)       (*((volatile unsigned char *)(x)))
#define REG_BIT_W(x, b)                                                     \
        REG(((unsigned long)(x) & 0xF0000000) | 0x02000000 |                \
              (((unsigned long)(x) & 0x000FFFFF) << 5) | ((b) << 2))
#define REG_BIT_H(x, b)                                                     \
        REG_H(((unsigned long)(x) & 0xF0000000) | 0x02000000 |              \
               (((unsigned long)(x) & 0x000FFFFF) << 5) | ((b) << 2))
#define REG_BIT_B(x, b)                                                     \
        REG_B(((unsigned long)(x) & 0xF0000000) | 0x02000000 |              \
               (((unsigned long)(x) & 0x000FFFFF) << 5) | ((b) << 2))

#endif /* REG_H_ */

 

 

下面是我的GPIO的测试INIT初始化代码,整整搞了4个小时,不容易啊,不过还是比较理想的。

像下面的GPIO_SET_OUTPUT(x.x)等,都是使用了REG(X)进行操作的。

 1     //配置RC3为输出,使用原NG的cc2538-dev的gpio.h文件实现。
 2     //先查看一下,GPIO_C的DIR方向寄存器的内容,RC3xxxx 0xxx,是1就为输出
 3     UARTprintf("RC3-DIR:%d\r\n",REG((GPIO_C_BASE) + GPIO_DIR)&0xff);
 4 
 5     //将RC3 xxxx 0xxx方向寄存器设为1
 6     GPIO_SET_OUTPUT(GPIO_C_BASE, GPIO_PIN_MASK(3));
 7 
 8     //打印出来确认一下RC3方向为1
 9     UARTprintf("RC3-DIR:%d\r\n",REG((GPIO_C_BASE) + GPIO_DIR)&0xff);
10 
11     //RC3为SET,打印确认
12     GPIO_SET_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3));
13     UARTprintf("SET-RC3-DATA:%d\r\n",GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));
14 
15     //RC3为CLR,打印确认
16     GPIO_CLR_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3));
17     UARTprintf("CLR-RC3-DATA:%d\r\n",GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));
18 
19     //RC3为SET,打印所有的GPIO确认一下,
20     GPIO_SET_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3));
21     UARTprintf("SET-PORTC-DATA:%d\r\n",REG((GPIO_C_BASE) + GPIO_DATA + ((0xff) << 2)));
22 
23     //RC3为CLR,打印所有的GPIO确认一下,
24     GPIO_CLR_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3));
25     UARTprintf("CLR-PROTC-DATA:%d\r\n",REG((GPIO_C_BASE) + GPIO_DATA + ((0xff) << 2)));
26 
27     //先读取值,以此值取反,达到闪烁LED目的测试
28     GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));
29     GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));
30     GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));
31     GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));
32     GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));

 

 

最后建一个时间事件进行点LED-RC3灯,如下代码

 1 /*-----------------------CC2538-GPIO的测试------------*/
 2 /*---------------------------------------------------------------------------*/
 3 PROCESS(cc2538_GPIO_DEV, "cc2538_GPIO_DEV");
 4 /*---------------------------------------------------------------------------*/
 5 PROCESS_THREAD(cc2538_GPIO_DEV, ev, data)
 6 {
 7   static struct etimer et04;
 8   static uint16_t count02=0;
 9   //intitRC3();
10 
11   PROCESS_BEGIN();
12   etimer_set(&et04, CLOCK_SECOND*1);
13 
14   while(1) {
15     PROCESS_WAIT_UNTIL(etimer_expired(&et04));
16 
17     etimer_reset(&et04);
18     UARTprintf("GPIO_DEV:%d\r\n",count02++);
19     GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));
20     PROCESS_YIELD();
21   }
22 
23   PROCESS_END();
24 }
25 //***********************************************************//
26 /*  所有自启动模式的PROCESSES  */
27 AUTOSTART_PROCESSES(
28                     &cc2538_GPIO_DEV
29 
30                       );

 

运行效果,打印出来的寄存器值,和数据手册对了一下,它们是正确的,这个PC3正在1秒反转一次进行闪烁,说明CC2538的dve的gpio.h功能测试通过了

 

从上面信息,我们可以看到,RC3能成功的进行操作,上面提到的REG宏功能,以及GPIO的初化的方法,其实它适用于所有MCU,只要你有对应的寄存器手册就可以了。

 

另外,GPIO的输入功能大同小意,可以直接跳过。想吃透这个OS/dev/的gpio-hal.h,还是要想办法把gpio-hal-arch.h搞定,总不能用着OS系统,按照裸机方法来写代码吧??

所以GPIO-HAL还要继续进行研究。。。。

 

 

时间:2020-09-27

之前,我们用CC2538的dve的gpio.h文件,把GPIO驱动起来了,今天我们利用gpio-hal-arch.h功能,实现与OS的链接,原作者的有点复杂,作了适当简化。

首先打开ng4.5-develop\examples\MYdemo\user\cc2538-dev的gpio-hal-arch.h文件,如下:

/*---------------------------------------------------------------------------*/
/**
 * \addtogroup cc2538
 * @{
 *
 * \defgroup cc2538-gpio-hal CC2538 GPIO HAL实现
 *
 * @{
 *
 * \file
 *     CC2538 GPIO HAL功能的头文件
 *
 * \note
 *     不直接包含此H标头
 */
/*---------------------------------------------------------------------------*/
#ifndef GPIO_HAL_ARCH_H_
#define GPIO_HAL_ARCH_H_
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "gpio.h"

#include <stdint.h>
/*---------------------------------------------------------------------------*/
#define PIN_TO_PORT(pin) (pin >> 3)
#define PIN_TO_NUM(pin) (pin % 8)
#define PIN_TO_PORT_BASE(pin) GPIO_PORT_TO_BASE(PIN_TO_PORT(pin))
/*---------------------------------------------------------------------------*/
#define gpio_hal_arch_init() do { /* 没做什么 */ } while(0)

/*  打开端口引脚的中断  */
#define gpio_hal_arch_interrupt_enable(port, p) do { \
  GPIO_ENABLE_INTERRUPT(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \
  NVIC_EnableIRQ(PIN_TO_PORT(p)); \
} while(0);

/*  关掉端口引脚的中断  */
#define gpio_hal_arch_interrupt_disable(port, p) \
  GPIO_DISABLE_INTERRUPT(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8))

/*  端口引脚配置成输入  */
#define gpio_hal_arch_pin_set_input(port, p) do { \
  GPIO_SOFTWARE_CONTROL(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \
  GPIO_SET_INPUT(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \
} while(0);


/*  端口引脚配置成输出  */
#define gpio_hal_arch_pin_set_output(port, p) do { \
  GPIO_SOFTWARE_CONTROL(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \
  GPIO_SET_OUTPUT(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \
} while(0);


/*  端口引脚配置成1  */
#define gpio_hal_arch_set_pin(port, p) \
  GPIO_SET_PIN(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8))

/*  端口引脚配置成0 */
#define gpio_hal_arch_clear_pin(port, p) \
  GPIO_CLR_PIN(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8))

/*  读取引脚的电平  */
#define gpio_hal_arch_read_pin(port, p) \
  (GPIO_READ_PIN(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)) == 0 ? 0 : 1)

/*---------------------------------------------------------------------------*/
#endif /* GPIO_HAL_ARCH_H_ */
/*---------------------------------------------------------------------------*/
/** @} */

 

 

这一次,我们关注的是:

1 /*  端口引脚配置成输出  */
2 #define gpio_hal_arch_pin_set_output(port, p) do { \
3   GPIO_SOFTWARE_CONTROL(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \
4   GPIO_SET_OUTPUT(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \
5 } while(0);
GPIO_SOFTWARE_CONTROL(x,x)是模式控制,就是说这个IO脚是软件直接操作,还是用于外设,如IIC  ADC等功能。

 

 

我们细仔看,发现(port, p)的port其实没什么用的,完全可以不理它,我们可以用0进行输入,最后研究出来是这样进行操作的

 1   /* 使用gpio-hal-arch.h文件实现 */
 2   gpio_hal_arch_pin_set_output(0,GPIO_PORT_PIN_TO_GPIO_HAL_PIN(GPIO_C_NUM, LEDS_ARCH_L3_PIN));     //OK
 3 
 4 
 5   GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));
 6   GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));
 7   GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));
 8   GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));
 9   GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));
10   GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));
11   GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));
12   GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));14 
15 
16   UARTprintf("HAL NO:0x%x\r\n",GPIO_PORT_PIN_TO_GPIO_HAL_PIN(GPIO_C_NUM, LEDS_ARCH_L3_PIN)); //换为GPIO HAL引脚号:0x13,这个3就是引脚号3

经过仿真发现,我们成功点亮了RC3,这里面关键的是GPIO_PORT_PIN_TO_GPIO_HAL_PIN(PORT, PIN),该定义位于MYdemo\user\cc2538-dev的gpio.h里面,属于CC2358-DEV部份。

我们将它进行UARTprintf进行打印,发现它的值为0x13,应该是3号PIN脚,理论上就是其它文件的实现的PORT号,PIN号。我们改一下:

1     /* 使用gpio-hal-arch.h文件实现 */
2   //gpio_hal_arch_pin_set_output(0,GPIO_PORT_PIN_TO_GPIO_HAL_PIN(GPIO_C_NUM, LEDS_ARCH_L3_PIN));     //OK
3   gpio_hal_arch_pin_set_output(0,0x13);     //OK
4 
5   GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));
6   GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(3)));

我的天,看看仿真的结果,RC3功能完全正常!那么0x11肯定是PIN号1了,同理0x12肯定是PIN号2了,同理0x14肯定是PIN号4了,

 

带着这个疑问,我们测试一下PIN号2,就用0x12:

1   gpio_hal_arch_pin_set_output(0,0x12);     //OK
2 
3   GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(2), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(2)));
4   GPIO_WRITE_PIN(GPIO_C_BASE, GPIO_PIN_MASK(2), ~GPIO_READ_PIN(GPIO_C_BASE, GPIO_PIN_MASK(2)));

我的天呀,看看仿真的结果,RC2被点亮了,哈哈哈!!!不过我们写成gpio_hal_arch_pin_set_output(0,GPIO_PORT_PIN_TO_GPIO_HAL_PIN(GPIO_C_NUM, LEDS_ARCH_L3_PIN)); 好一点,因为可读性高一点,比竟有时要让别人阅读你的代码。

如果你天天写成(0,0x12)的话,肯定要被领导P的。另外0也不能写的,应该写成GPIO_HAL_NULL_PORT被定义成0的,看来数字符号难于理解,英文字母才能更好的表示用意,当然注示还是用中文的^_^

 

总结:在多数情况下,开发者要以二进制或16进制的数学符号,去理解编译器的行为,实际上也就是OS原作者的思想!(本质是数学)

还有一个ng4.5-develop\os\dev的gpio-hal.h文件,研究完这个OS/dev的gpio-hal.h,基本上GPIO就差不多了,最后就是每个RA RC RB引脚去测试一下,加深理解,从而换其它芯片时能快速形成应用,为自己加油!!

 

时间:2020-10-12

在ng4.5-develop\os\dev的gpio-hal.h文件中,其实它分为俩大部分,gpio-hal.h第1部份如下:

  1 /**
  2  * \addtogroup dev
  3  * @{
  4  *
  5  * \defgroup: gpio-hal GPIO硬件抽象层
  6  *
  7  *
  8  * @{
  9  *
 10  * \file
 11  *     GPIO HAL的头文件
 12  */
 13 
 14 
 15 /*---------------------------------------------------------------------------*/
 16 #ifndef GPIO_HAL_H_
 17 #define GPIO_HAL_H_
 18 
 19 
 20 /*---------------------------------------------------------------------------*/
 21 #include "contiki.h"
 22 #include <stdint.h>
 23 
 24 
 25 /*---------------------------------------------------------------------------*/
 26 /**
 27  * \brief 指定HAL是否应支持端口/引脚约定
 28  *
 29  * Some MCUs specify GPIOs as a port/pin combination, whereas some others
 30  * only use a pin number. Our GPIO HAL supports both conventions in a portable
 31  * fashion and this define is used to set the HAL in the desired of the two
 32  * modes.
 33  *
 34  * The port developer should define GPIO_HAL_CONF_PORT_PIN_NUMBERING as a if
 35  * the platform uses port/pin numbering, or to 0 if the platform only uses
 36  * a simple number.
 37  */
 38 #ifdef GPIO_HAL_CONF_PORT_PIN_NUMBERING    //cc2538-def.h有约
 39 #define GPIO_HAL_PORT_PIN_NUMBERING GPIO_HAL_CONF_PORT_PIN_NUMBERING   //选定
 40 #else
 41 #define GPIO_HAL_PORT_PIN_NUMBERING 1
 42 #endif
 43 
 44 
 45 /*---------------------------------------------------------------------------*/
 46 /**
 47  * \brief 指定是否需要基于软件的引脚切换
 48  *
 49  * Some MCUs allow GPIO pin toggling via direct register access. For these
 50  * MCUs, define GPIO_HAL_CONF_ARCH_SW_TOGGLE to 0 and then implement
 51  * gpio_hal_arch_toggle_pin() and gpio_hal_arch_toggle_pins()
 52  *
 53  * \sa gpio_hal_arch_toggle_pin()
 54  * \sa gpio_hal_arch_toggle_pins()
 55  */
 56 #ifdef GPIO_HAL_CONF_ARCH_SW_TOGGLE      //cc2538-def.h有约
 57 #define GPIO_HAL_ARCH_SW_TOGGLE GPIO_HAL_CONF_ARCH_SW_TOGGLE
 58 #else
 59 #define GPIO_HAL_ARCH_SW_TOGGLE 1
 60 #endif
 61 
 62 
 63 /*---------------------------------------------------------------------------*/
 64 /**
 65  * \brief 方便宏,用于此宏的端口参数
 66  *
 67  * Use this as the port \e argument of macros when GPIO_HAL_PORT_PIN_NUMBERING
 68  * is zero
 69  */
 70 #define GPIO_HAL_NULL_PORT      0   //暂时理解为,不使用PORT端口参数
 71 /*---------------------------------------------------------------------------*/
 72 
 73 typedef uint8_t gpio_hal_pin_t;      //GPIO引脚号表示
 74 typedef uint8_t gpio_hal_port_t;     //表示端口的数据结构
 75 typedef uint32_t gpio_hal_pin_cfg_t; //GPIO引脚配置,是不是很多余?用uintXX_t不好?
 76 
 77 /**
 78  * \brief 指定设备上的引脚总数
 79  *
 80  * 如果GPIO_HAL_PORT_PIN_NUMBERING为非零,则此宏无效。
 81  */
 82 #ifdef GPIO_HAL_CONF_PIN_COUNT
 83 #define GPIO_HAL_PIN_COUNT GPIO_HAL_CONF_PIN_COUNT
 84 #else
 85 #define GPIO_HAL_PIN_COUNT 32
 86 #endif
 87 
 88 #if GPIO_HAL_PIN_COUNT > 32 && !GPIO_HAL_PORT_PIN_NUMBERING
 89 typedef uint64_t gpio_hal_pin_mask_t;
 90 #else
 91 /**
 92  * \brief GPIO 引脚掩码表示
 93  *
 94  * 可用于使用单个变量表示多个引脚的掩码
 95  * 当GPIO_HAL_PORT_PIN_NUMBERING为非零时,此类变量只能用于表示同一端口内的引脚。
 96  */
 97 typedef uint32_t gpio_hal_pin_mask_t;
 98 #endif
 99 
100 
101 /*---------------------------------------------------------------------------*/
102 #if GPIO_HAL_PORT_PIN_NUMBERING
103 typedef void (*gpio_hal_callback_t)(gpio_hal_port_t port,
104                                     gpio_hal_pin_mask_t pin_mask);
105 #else
106 typedef void (*gpio_hal_callback_t)(gpio_hal_pin_mask_t pin_mask);
107 #endif
108 
109 
110 /*---------------------------------------------------------------------------*/
111 #define GPIO_HAL_PIN_CFG_PULL_NONE        0x00
112 #define GPIO_HAL_PIN_CFG_PULL_UP          0x01
113 #define GPIO_HAL_PIN_CFG_PULL_DOWN        0x02
114 #define GPIO_HAL_PIN_CFG_PULL_MASK        (GPIO_HAL_PIN_CFG_PULL_UP | \
115                                            GPIO_HAL_PIN_CFG_PULL_DOWN)
116 
117 #define GPIO_HAL_PIN_CFG_HYSTERESIS       0x10
118 
119 #define GPIO_HAL_PIN_CFG_EDGE_NONE        0x00
120 #define GPIO_HAL_PIN_CFG_EDGE_RISING      0x04
121 #define GPIO_HAL_PIN_CFG_EDGE_FALLING     0x08
122 #define GPIO_HAL_PIN_CFG_EDGE_BOTH        (GPIO_HAL_PIN_CFG_EDGE_RISING | \
123                                            GPIO_HAL_PIN_CFG_EDGE_FALLING)
124 
125 #define GPIO_HAL_PIN_CFG_INT_DISABLE      0x00
126 #define GPIO_HAL_PIN_CFG_INT_ENABLE       0x80
127 #define GPIO_HAL_PIN_CFG_INT_MASK         0x80
128 
129 
130 /*---------------------------------------------------------------------------*/
131 /**
132  * \brief GPIO 事件处理程序的数据类型
133  *
134  * GPIO事件处理程序是在引脚触发事件时调用的函数。 可以通过设置相应引脚的位置,
135  * 但在\ e pin_mask中,注册同一处理程序以处理多个引脚的事件。
136  * 如果GPIO_HAL_PORT_PIN_NUMBERING不为零,则每个端口需要一个单独的处理程序。
137  */
138 typedef struct gpio_hal_event_handler_s {
139   struct gpio_hal_event_handler_s *next;
140   gpio_hal_callback_t handler;
141 #if GPIO_HAL_PORT_PIN_NUMBERING
142   gpio_hal_port_t port;
143 #endif
144   gpio_hal_pin_mask_t pin_mask;
145 } gpio_hal_event_handler_t;
146 
147 
148 /*---------------------------------------------------------------------------*/
149 #define GPIO_HAL_PIN_UNKNOWN              0xFF    //未知 GPIO
150 
151 
152 /*---------------------------------------------------------------------------*/
153 /**
154  * \name 核心 GPIO 功能
155  *
156  * HAL 本身实现的功能
157  * @{
158  */
159 
160 void gpio_hal_init(void);    //初始化 Gpio HAL
161 
162 /**
163  * \brief 注册一个函数,每当引脚触发事件时,请调用该函数
164  * \param handler The handler representation
165  *
166  * The handler must be pre-allocated statically by the caller.
167  *
168  * This function can be used to register a function to be called by the HAL
169  * whenever a GPIO interrupt occurs.
170  *
171  * \sa gpio_hal_event_handler
172  */
173 void gpio_hal_register_handler(gpio_hal_event_handler_t *handler);
174 
175 #if GPIO_HAL_PORT_PIN_NUMBERING
176 /**
177  * \brief 独立于平台的 GPIO 事件处理程序
178  * \param port The GPIO port, if applicable
179  * \param pins OR mask of pins that generated an event
180  *
181  * Whenever a GPIO input interrupt occurs (edge or level detection) and an ISR
182  * is triggered, the ISR must call this function, passing as argument an ORd
183  * mask of the pins that triggered the interrupt. This function will then
184  * call the registered event handlers (if any) for the pins that triggered the
185  * event. The platform code should make no assumptions as to the order that
186  * the handlers will be called.
187  *
188  * If a pin set in the mask has an event handler registered, this function
189  * will call the registered handler.
190  *
191  * If GPIO_HAL_PORT_PIN_NUMBERING is non-zero the function will also accept
192  * as its first argument the port associated to the pins that triggered the
193  * edge detection.
194  *
195  * This function will not clear any CPU interrupt flags, this should be done
196  * by the calling ISR.
197  *
198  * \sa gpio_hal_register_handler
199  */
200 void gpio_hal_event_handler(gpio_hal_port_t port, gpio_hal_pin_mask_t pins);
201 #else
202 void gpio_hal_event_handler(gpio_hal_pin_mask_t pins);
203 #endif
204 
205 /**
206  * \brief 将引脚转换为引脚掩码
207  * \param pin The pin
208  * \return The corresponding mask
209  */
210 #define gpio_hal_pin_to_mask(pin) ((gpio_hal_pin_mask_t)1 << (pin))
211 /** @} */

 

gpio-hal.h第2部份,经过分析源码发现,每个函数的套路都是一模一样的,我们取一个进行研究,达到举1反3:

 1 /*---------------------------------------------------------------------------*/
 2 /**
 3  * \name 由平台代码提供的GPIO引脚操作功能。
 4  *
 5  * 所有功能都有两种方式:
 6  * 第1种->当 GPIO_HAL_PORT_PIN_NUMBERING 非0时,期望将gpio_hal_port_t作为参数
 7  * 第2种->当 GPIO_HAL_PORT_PIN_NUMBERING 为0时,不期望将gpio_hal_port_t作为参数
 8  *
 9  * 为了要达到代码的可移植性,所有与平台无关的代码都应使用这些宏来操纵GPIO,而不是
10  * 直接使用port_ / no_port_函数。
11  *
12  *
13  * 下面的所有功能必须由平台的开发人员提供。HAL为开发人员提供了许多有关如何提供所需功能的选项。
14  *
15  * -开发人员可以提供符号。 例如,开发人员可以创建一个.c文件并实现一个名为
16  * gpio_hal_arch_set_port_pin()的函数。 在这种情况下,开发人员只需为适用的
17  * gpio_hal_arch_port_foo / gpio_hal_arch_no_port_foo提供符号。
18  *
19  * -开发人员可以提供一个类似于函数的宏,该宏的名称与此处声明的操作宏之一相同。 在这种情况下,
20  * 预处理器将删除此处的声明。 例如,开发人员可以执行以下操作:
21  *   \code
22  *   #define gpio_hal_arch_write_pin(port, pin, v) sdk_function(port, pin, v)
23  *   \endcode
24  *
25  * -开发人员可以提供静态内联实现。 为此工作,开发人员可以执行以下操作:
26  *   \code
27  *   #define gpio_hal_arch_set_pin(port, pin) set_pin(port, pin)
28  *   static inline void set_pin(gpio_hal_port_t port, gpio_hal_pin_t pin) { ... }
29  *   \endcode
30  *
31  * 在后两种情况下,开发人员可能会在头文件中提供实现。 在这种情况下,平台的配置文件之一
32  * 必须为该标头的名称定义GPIO_HAL_CONF_ARCH_HDR_PATH文件。 例如:
33  * \code
34  * #define GPIO_HAL_CONF_ARCH_HDR_PATH          "dev/gpio-hal-arch.h"
35  * \endcode
36  * @{
37  */
38 
39 /*---------------------------------------------------------------------------*/
40 /* Include Arch-Specific conf */
41 #ifdef GPIO_HAL_CONF_ARCH_HDR_PATH
42 #include "gpio-hal-arch.h"
43 #endif /* GPIO_HAL_CONF_ARCH_HDR_PATH */
44 
45 /*---------------------------------------------------------------------------*/
46 #ifndef gpio_hal_arch_pin_set_output
47 /**
48  * \brief 将引脚配置为GPIO输出
49  * \param port The GPIO port
50  * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
51  *
52  * The implementation of this function also has to make sure that \e pin is
53  * configured as software-controlled GPIO.
54  *
55  * It is the platform developer's responsibility to provide an implementation.
56  *
57  * The implementation can be provided as a global symbol, an inline function
58  * or a function-like macro, as described above.
59  *
60  * \note Code should not call this function directly. Use GPIO manipulation
61  * macros instead.
62  */
63 void gpio_hal_arch_port_pin_set_output(gpio_hal_port_t port,
64                                        gpio_hal_pin_t pin);
65 
66 /**
67  * \brief 将引脚配置为GPIO输出
68  * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
69  *
70  * The implementation of this function also has to make sure that \e pin is
71  * configured as software-controlled GPIO.
72  *
73  * It is the platform developer's responsibility to provide an implementation.
74  *
75  * The implementation can be provided as a global symbol, an inline function
76  * or a function-like macro, as described above.
77  *
78  * \note Code should not call this function directly. Use GPIO manipulation
79  * macros instead.
80  */
81 void gpio_hal_arch_no_port_pin_set_output(gpio_hal_pin_t pin);
82 
83 #if GPIO_HAL_PORT_PIN_NUMBERING
84 #define gpio_hal_arch_pin_set_output(port, pin) \
85   gpio_hal_arch_port_pin_set_output(port, pin)
86 #else
87 #define gpio_hal_arch_pin_set_output(port, pin) \
88   gpio_hal_arch_no_port_pin_set_output(pin)
89 #endif /* GPIO_HAL_PORT_PIN_NUMBERING */
90 #endif /* gpio_hal_arch_pin_set_output */

前面先定义好2个功能函数,这里是gpio_hal_arch_port_pin_set_output(xx,xx)  和  gpio_hal_arch_no_port_pin_set_output(xx)

然后在利用GPIO_HAL_PORT_PIN_NUMBERING条件,是否使用PORT参数,过程实现如下:

1 #if GPIO_HAL_PORT_PIN_NUMBERING
2 #define gpio_hal_arch_pin_set_output(port, pin) \
3   gpio_hal_arch_port_pin_set_output(port, pin)
4 #else
5 #define gpio_hal_arch_pin_set_output(port, pin) \
6   gpio_hal_arch_no_port_pin_set_output(pin)
7 #endif /* GPIO_HAL_PORT_PIN_NUMBERING */

上面这个gpio_hal_arch_pin_set_output功能是在cc2538-dev的gpio-hal-arch.h已经实现了的,我们在这之前也已经测试过了!!果然很有灵性,

1  * -开发人员可以提供一个类似于函数的宏,该宏的名称与此处声明的操作宏之一相同。 在这种情况下,
2  * 预处理器将删除此处的声明。 例如,开发人员可以执行以下操作:
3  *   \code
4  *   #define gpio_hal_arch_pin_set_output(port, pin) sdk_function(port, pin)
5  *   \endcode

我们在回到cc2538-dev的gpio-hal-arch.h的内容:

1 /*  端口引脚配置成输出  */
2 #define gpio_hal_arch_pin_set_output(port, p) do { \
3   GPIO_SOFTWARE_CONTROL(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \
4   GPIO_SET_OUTPUT(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \
5 } while(0);

这些逻辑关系的文件要来回看、来回阅读,才很很好的理解,为了一目了然  我们整理在一个文件里:

 1 /*---------------------------------------------------------------------------*/
 2 //在\os\dev的gpio-hal.h的信息
 3 #ifndef gpio_hal_arch_pin_set_output
 4 void gpio_hal_arch_port_pin_set_output(gpio_hal_port_t port,
 5                                        gpio_hal_pin_t pin);
 6 
 7 
 8 void gpio_hal_arch_no_port_pin_set_output(gpio_hal_pin_t pin);
 9 
10 #if GPIO_HAL_PORT_PIN_NUMBERING
11 #define gpio_hal_arch_pin_set_output(port, pin) \
12   gpio_hal_arch_port_pin_set_output(port, pin)
13 #else
14 #define gpio_hal_arch_pin_set_output(port, pin) \
15   gpio_hal_arch_no_port_pin_set_output(pin)
16 #endif /* GPIO_HAL_PORT_PIN_NUMBERING */
17 #endif /* gpio_hal_arch_pin_set_output */
18 
19 
20 
21 /*---------------------------------------------------------------------------*/
22 //在cc2538-dev的gpio-hal-arch.h的信息
23 /*  端口引脚配置成输出  */
24 #define gpio_hal_arch_pin_set_output(port, p) do { \
25   GPIO_SOFTWARE_CONTROL(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \
26   GPIO_SET_OUTPUT(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \
27 } while(0);
28 
29 
30 
31 /*---------------------------------------------------------------------------*/
32 // 我们在进程中使用的信息
33 /* 端口引脚配置成输出  */
34 /* 使用gpio-hal-arch.h文件已经实现dev的gpio-hal.h内容 */
35   gpio_hal_arch_pin_set_output(0,GPIO_PORT_PIN_TO_GPIO_HAL_PIN(GPIO_C_NUM, LEDS_ARCH_L3_PIN));     //OK

这样看够清楚了吧?哈哈。说白了define时,只要gpio-hal-arch.h的名字和gpio-hal.h的名字一样,就直接被转移到了gpio-hal-arch.h功能,

 所有的细节都在gpio-hal-arch.h文件内,你明白了吗??

posted on 2020-09-20 23:11  木子剑  阅读(437)  评论(0编辑  收藏  举报