查看: 290|回复: 0

[原创] 【S32K146 RT-thread】之 PIN 驱动

[复制链接]
  • TA的每日心情
    奋斗
    3 天前
  • 签到天数: 594 天

    [LV.9]以坛为家II

    51

    主题

    2222

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    7062
    最后登录
    2024-4-27
    发表于 2024-1-6 07:43:45 | 显示全部楼层 |阅读模式
    本帖最后由 andeyqi 于 2024-1-6 07:43 编辑

    概述:
            在RT-Thread中,PIN(引脚)驱动层主要负责对硬件引脚进行控制和管理。该层的设计旨在提供一种通用的、可移植的方式,使应用程序能够方便地与硬件引脚进行交互,而不需要关心底层硬件的具体细节。PIN 驱动提供了硬件抽象层,使得相同的应用程序代码可以在不同的硬件平台上运行。开发者在移植 RT-Thread 到新的硬件平台时,只需要实现相应平台的 PIN 驱动,而无需修改应用层的代码。右侧链接为官方文档对PIN驱动架构的详细描述(RT-thread PIN驱动介绍)。根据官方文档的介绍可以知道,RT-thread PIN 驱动框架通过如下几个接口和BSP芯片的GPIO对接,我们按照要求适配好这几个接口就完成了PIN 驱动框架和硬件的对接,接口如下:

    pin.jpg


    • rt_pin_get() 接口适配
    该接口通过传入pin 的name 获取pin 脚号,然后用户通过 pin number 完成GPIO 的输入、输出及中断控制。具体实现代码如下:

    1. static rt_base_t s32kxxx_pin_get(const char * name)
    2. {
    3.     int pin = 0;
    4.     int hw_port_num, hw_pin_num = 0;
    5.     int i, name_len;

    6.     name_len = strlen(name);

    7.     if ((name_len < 4) || (name_len >= 6))
    8.     {
    9.         return -1;
    10.     }

    11.     if ((name[0] != 'P') || (name[2] != '.'))
    12.     {
    13.         return -1;
    14.     }

    15.     if ((name[1] >= 'A') && (name[1] <= 'E'))
    16.     {
    17.         hw_port_num = (int)(name[1] - 'A');
    18.     }
    19.     else
    20.     {
    21.         return -1;
    22.     }

    23.     for (i = 3; i < name_len; i++)
    24.     {
    25.         hw_pin_num *= 10;
    26.         hw_pin_num += name[i] - '0';
    27.     }

    28.     pin = PIN_NUM(hw_port_num, hw_pin_num);

    29.     return pin;

    30. }
    复制代码


    使用的S32K146 芯片引脚是按照PTAx,我们对应成PA.x的形式,例如要获取PTA2 的pin number ,按照如下方式调用即可:
    1. pin_number = rt_pin_get("PA.2");
    复制代码

    • rt_mode()接口适配
    该接口使用rt_pin_get()接口返回的pin number 配置GPIO 的输入输出属性,及上下拉配置,在S32K146上适配代码如下:
    1. /**
    2.   * @brief  set pin mode
    3.   * @param  pin, mode
    4.   * @retval None
    5.   */
    6. static void s32kxxx_pin_mode(rt_device_t dev, rt_base_t pin, rt_uint8_t mode)
    7. {
    8.     const struct pin_index *index = NULL;

    9.     index = get_pin(pin);
    10.     if (index == NULL)
    11.     {
    12.         return;
    13.     }

    14.     PINS_DRV_SetMuxModeSel(index->port,index->pin,PORT_MUX_AS_GPIO);

    15.     switch(mode)
    16.     {
    17.     case PIN_MODE_OUTPUT:
    18.     case PIN_MODE_OUTPUT_OD:
    19.         PINS_DRV_SetPinDirection(index->gpio,index->pin,GPIO_OUTPUT_DIRECTION);
    20.         break;
    21.     case PIN_MODE_INPUT:
    22.         PINS_DRV_SetPullSel(index->port,index->pin,PORT_INTERNAL_PULL_NOT_ENABLED);
    23.         PINS_DRV_SetPinDirection(index->gpio,index->pin,GPIO_INPUT_DIRECTION);
    24.         break;
    25.     case PIN_MODE_INPUT_PULLUP:
    26.         PINS_DRV_SetPullSel(index->port,index->pin,PORT_INTERNAL_PULL_UP_ENABLED);
    27.         PINS_DRV_SetPinDirection(index->gpio,index->pin,GPIO_INPUT_DIRECTION);
    28.         break;
    29.     case PIN_MODE_INPUT_PULLDOWN:
    30.         PINS_DRV_SetPullSel(index->port,index->pin,PORT_INTERNAL_PULL_DOWN_ENABLED);
    31.         PINS_DRV_SetPinDirection(index->gpio,index->pin,GPIO_INPUT_DIRECTION);
    32.         break;
    33.     default:
    34.         break;
    35.     }
    36. }
    复制代码

    • rt_pin_write()接口适配:
    该接口使用rt_pin_get()接口返回的pin number 配置GPIO 的输出高低电平设置适配代码如下:

    1. /**
    2.   * @brief  pin write
    3.   * @param   pin, valuie
    4.   * @retval None
    5.   */
    6. static void s32kxxx_pin_write(rt_device_t dev, rt_base_t pin, rt_uint8_t value)
    7. {
    8.     const struct pin_index *index = NULL;

    9.     index = get_pin(pin);
    10.     if (index == NULL)
    11.     {
    12.         return;
    13.     }
    14.     PINS_DRV_WritePin(index->gpio,index->pin,value);
    15. }
    复制代码

    • rt_pin_read()接口适配
    该接口使用rt_pin_get()接口返回的pin number 读取 GPIO 的输入引脚状态,设置适配代码如下:
    1. /**
    2.   * @brief  pin read
    3.   * @param  dev, pin
    4.   * @retval None
    5.   */
    6. static rt_int8_t s32kxxx_pin_read(rt_device_t dev, rt_base_t pin)
    7. {
    8.     int value = PIN_LOW;
    9.     const struct pin_index *index = NULL;

    10.     index = get_pin(pin);
    11.     if (index == NULL)
    12.     {
    13.         return value;
    14.     }

    15.     value = (PINS_DRV_ReadPins(index->gpio) & (0x01 << (index->pin))) ? PIN_HIGH : PIN_LOW;

    16.     return value;
    17. }
    复制代码

    • rt_irq_attach_irq 接口适配
    该接口绑定rt_pin_get()接口返回的pin number 对应的中断回调函数,设置适配代码如下:
    1. /**
    2.   * @brief  pin irq attach
    3.   * @param  device, pin, mode
    4.   * @retval None
    5.   */
    6. static rt_err_t s32kxxx_pin_attach_irq(struct rt_device *device, rt_base_t pin,
    7.                               rt_uint8_t mode, void (*hdr)(void *args), void *args)
    8. {
    9.     rt_base_t level;
    10.     rt_int32_t hdr_index = -1;

    11.     hdr_index = pin/32;
    12.     if (hdr_index < 0 || hdr_index >= 5)
    13.     {
    14.         return -RT_EINVAL;
    15.     }

    16.     level = rt_hw_interrupt_disable();
    17.     if (pin_irq_hdr_tab[hdr_index].pin == pin &&
    18.         pin_irq_hdr_tab[hdr_index].hdr == hdr &&
    19.         pin_irq_hdr_tab[hdr_index].mode == mode &&
    20.         pin_irq_hdr_tab[hdr_index].args == args)
    21.     {
    22.         rt_hw_interrupt_enable(level);
    23.         return RT_EOK;
    24.     }
    25.     if (pin_irq_hdr_tab[hdr_index].pin != -1)
    26.     {
    27.         rt_hw_interrupt_enable(level);
    28.         return -RT_EFULL;
    29.     }
    30.     pin_irq_hdr_tab[hdr_index].pin = pin;
    31.     pin_irq_hdr_tab[hdr_index].hdr = hdr;
    32.     pin_irq_hdr_tab[hdr_index].mode = mode;
    33.     pin_irq_hdr_tab[hdr_index].args = args;
    34.     rt_hw_interrupt_enable(level);

    35.     return RT_EOK;
    36. }
    复制代码
    • rt_pin_detach_irq接口适配
    该接口解除绑定rt_pin_get()接口返回的pin number 对应的中断回调函数,设置适配代码如下:
    1. /**
    2.   * @brief  pin irq detach
    3.   * @param  device, pin
    4.   * @retval None
    5.   */
    6. static rt_err_t s32kxxx_pin_detach_irq(struct rt_device *device, rt_base_t pin)
    7. {
    8.     rt_base_t level;
    9.     rt_int32_t hdr_index = -1;

    10.     hdr_index = pin/32;
    11.     if (hdr_index < 0 || hdr_index >= 5)
    12.     {
    13.         return -RT_EINVAL;
    14.     }

    15.     level = rt_hw_interrupt_disable();
    16.     if (pin_irq_hdr_tab[hdr_index].pin == -1)
    17.     {
    18.         rt_hw_interrupt_enable(level);
    19.         return RT_EOK;
    20.     }
    21.     pin_irq_hdr_tab[hdr_index].pin = -1;
    22.     pin_irq_hdr_tab[hdr_index].hdr = RT_NULL;
    23.     pin_irq_hdr_tab[hdr_index].mode = 0;
    24.     pin_irq_hdr_tab[hdr_index].args = RT_NULL;
    25.     rt_hw_interrupt_enable(level);

    26.     return RT_EOK;
    27. }
    复制代码
    • rt_pin_irq_enable接口适配
    该接口开启、关闭rt_pin_get()接口返回的pin number 对应的中断,设置适配代码如下:

    1. /**
    2.   * @brief  pin irq enable
    3.   * @param  device, pin, enabled
    4.   * @retval None
    5.   */
    6. static rt_err_t s32kxxx_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled)
    7. {
    8.     const struct pin_index *index;
    9.     rt_base_t level;
    10.     rt_int32_t hdr_index = -1;
    11.     port_interrupt_config_t trigger_mode;

    12.     index = get_pin(pin);
    13.     if (index == RT_NULL)
    14.     {
    15.         return -RT_EINVAL;
    16.     }

    17.     if (enabled == PIN_IRQ_ENABLE)
    18.     {
    19.         hdr_index = pin/32;
    20.         if (hdr_index < 0 || hdr_index >= 5)
    21.         {
    22.             return -RT_EINVAL;
    23.         }

    24.         level = rt_hw_interrupt_disable();
    25.         if (pin_irq_hdr_tab[hdr_index].pin == -1)
    26.         {
    27.             rt_hw_interrupt_enable(level);
    28.             return -RT_EINVAL;
    29.         }
    30.         switch (pin_irq_hdr_tab[hdr_index].mode)
    31.         {
    32.             case PIN_IRQ_MODE_RISING:
    33.                 trigger_mode = PORT_INT_RISING_EDGE;
    34.                 break;
    35.             case PIN_IRQ_MODE_FALLING:
    36.                 trigger_mode = PORT_INT_FALLING_EDGE;
    37.                 break;
    38.             case PIN_IRQ_MODE_RISING_FALLING:
    39.                 trigger_mode = PORT_INT_EITHER_EDGE;
    40.                 break;
    41.             case PIN_IRQ_MODE_HIGH_LEVEL:
    42.                 trigger_mode = PORT_INT_LOGIC_ONE;
    43.                 break;
    44.             case PIN_IRQ_MODE_LOW_LEVEL:
    45.                 trigger_mode = PORT_INT_LOGIC_ZERO;
    46.                 break;
    47.             default:
    48.                 rt_hw_interrupt_enable(level);
    49.                 return -RT_EINVAL;
    50.         }

    51.         PINS_DRV_SetPinIntSel(index->port,index->pin,trigger_mode);

    52.         INT_SYS_SetPriority(index->irq, 0);
    53.         INT_SYS_EnableIRQ(index->irq);

    54.         rt_hw_interrupt_enable(level);

    55.     }
    56.     else if (enabled == PIN_IRQ_DISABLE)
    57.     {
    58.         PINS_DRV_SetPinIntSel(index->port,index->pin,PORT_DMA_INT_DISABLED);
    59.         INT_SYS_DisableIRQ(index->irq);
    60.     }
    61.     else
    62.     {
    63.         return -RT_EINVAL;
    64.     }

    65.     return RT_EOK;
    66. }

    67. const static struct rt_pin_ops s32kxxx_pin_ops =
    68. {
    69.     .pin_mode = s32kxxx_pin_mode,
    70.     .pin_write = s32kxxx_pin_write,
    71.     .pin_read = s32kxxx_pin_read,
    72.     .pin_get = s32kxxx_pin_get,
    73.     .pin_attach_irq = s32kxxx_pin_attach_irq,
    74.     .pin_detach_irq= s32kxxx_pin_detach_irq,
    75.     .pin_irq_enable = s32kxxx_pin_irq_enable,
    76. };


    77. int rt_hw_pin_init(void)
    78. {
    79.     int result;

    80.     result = rt_device_pin_register("pin", &s32kxxx_pin_ops, RT_NULL);

    81.     return result;
    82. }

    83. INIT_BOARD_EXPORT(rt_hw_pin_init);
    复制代码
    添加如下测试代码,配置gpio 为双边沿触发。
    1. void acc_int_irq(void * data)
    2. {
    3.     rt_base_t acc_pin;
    4.     acc_pin = rt_pin_get(ACC_DET);
    5.    
    6.     if(rt_pin_read(acc_pin))
    7.     {
    8.       rt_kprintf("rising .\n");
    9.     }
    10.     else
    11.     {
    12.       rt_kprintf("falling .\n");
    13.     }
    14. }


    15. int main(void)
    16. {
    17.     rt_base_t acc_pin;
    18.     rt_int8_t acc_status = 0,acc_temp = 0;

    19.     board_power_on();

    20.     acc_pin = rt_pin_get(ACC_DET);
    21.     rt_pin_mode(acc_pin,PIN_MODE_INPUT);
    22.    
    23.     rt_pin_attach_irq(acc_pin,PIN_IRQ_MODE_RISING_FALLING,acc_int_irq,RT_NULL);
    24.    
    25.     rt_pin_irq_enable(acc_pin,PIN_IRQ_ENABLE);

    26.     while(1)
    27.     {
    28.         acc_temp = rt_pin_read(acc_pin);
    29.         if(acc_temp != acc_status)
    30.         {
    31.             rt_kprintf("acc status %d -> %d.\n",acc_status,acc_temp);
    32.             acc_status = acc_temp;
    33.         }

    34.         rt_thread_mdelay(100);
    35.     }

    36.     return RT_EOK;
    37. }
    复制代码
    上电运行,拉高拉低对应的测试GPIO,对应的中断回调函数已经可以正常检出上升沿/下降沿,轮询GPIO 状态也可以获取到状态。
    gpio_test.jpg


    代码路径:

    该会员没有填写今日想说内容.
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-4-28 06:55 , Processed in 0.108269 second(s), 19 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表