回答

收藏

《2023 DigiKey 汽车应用创意挑战赛》 PIN驱动适配

#竞赛 #竞赛 1836 人阅读 | 0 人回复 | 2024-01-11

本帖最后由 andeyqi 于 2024-1-12 09:52 编辑

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

函数描述
rt_pin_get()获取引脚编号
rt_pin_mode()设置引脚模式
rt_pin_write()设置引脚电平
rt_pin_read()读取引脚电平
rt_pin_attach_irq()绑定引脚中断回调函数
rt_pin_irq_enable()使能引脚中断
rt_pin_detach_irq()脱离引脚中断回调函数

  • 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. <blockquote>/**
复制代码
  • 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);
复制代码
至此已经适配好了PIN驱动。我们可以在此基础行控制GPIO完成CAN 收发器GPIO 模拟的I2C 接口的控制。

分享到:
回复

使用道具 举报

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

本版积分规则

关闭

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