lilijin1995 发表于 2022-3-28 22:42

【AT-START-F425测评】+ USB HID设备Joystick开发体验与外设ADC DMA...

本帖最后由 lilijin1995 于 2022-3-28 22:49 编辑

一、知识准备1. 初探USB规格书中关于usb部分的介绍如下图:从上图可以了解到雅特力usb支持otg模式,支持全速12Mb/s,有1280byte专用缓存,并支持8个输入8个输出端点等信息;接着我们看参考手册中usb的介绍,USB OTG 全速的介绍在第二十章,下面是OTGFS的系统结构框图,更详细部分请直接阅读参考手册了解。2. 初探ADCAT32F425的ADC特性:ADC的框图3.初探GPIO简介:AT32F425 支持多达 55 个双向 I/O 引脚,分别为 PA0-PA15、PB0-PB15、PC0-PC15、PD2、PF0-PF1、PF4-PF7 每个引脚都可以实现与外部的通讯、控制以及数据采集的功能。每个引脚都支持通用功能输入输出(GPIO)或复用功能输入输出(IOMUX)。每个引脚都可以软件配置成浮空输入、上拉/下拉输入、模拟输入/输出、通用推挽/开漏输出、复用推挽/开漏输出。每个引脚都有独立的弱上拉/下拉功能。每个引脚都可以软件配置输出驱动能力以及输出信号斜率。每个引脚都可以配置为外部中断输入。每个引脚都支持配置锁定功能。GPIO基本结构
二、硬件设计用到PA4和PA5去采集摇杆模块的XY,再用PB0~PB7作为按键;
三、软件设计
在\project\at_start_f425\examples\usb_device\custom_hid基础上修改得来;


以下是A4和PA5作为ADC 的ch4和ch5 的DMA模式,B0~PB7作为gpio输入的初始化配置;
/**
* @briefjoystick gpio configuration.
* @paramnone
* @retval none
*/
static void Joy_gpio_config(void)
{
      //X-Y
      gpio_init_type gpio_initstructure;
      crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

      gpio_default_para_init(&gpio_initstructure);
      gpio_initstructure.gpio_mode = GPIO_MODE_ANALOG;
      gpio_initstructure.gpio_pins = GPIO_PINS_4 | GPIO_PINS_5 ;
      gpio_init(GPIOA, &gpio_initstructure);

      //Button1~8
      crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);      
      gpio_default_para_init(&gpio_initstructure);
      gpio_initstructure.gpio_pull=GPIO_PULL_UP;
      gpio_initstructure.gpio_mode = GPIO_MODE_INPUT;
      gpio_initstructure.gpio_pins = GPIO_PINS_0|GPIO_PINS_1|GPIO_PINS_2|GPIO_PINS_3
                                                                  |GPIO_PINS_4|GPIO_PINS_5|GPIO_PINS_6|GPIO_PINS_7;
      gpio_init(GPIOB, &gpio_initstructure);
      
}


/**
* @briefdma configuration.
* @paramnone
* @retval none
*/
static void Joy_dma_config(void)
{
      dma_init_type dma_init_struct;
      crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
      nvic_irq_enable(DMA1_Channel1_IRQn, 0, 0);
      dma_reset(DMA1_CHANNEL1);

      dma_flexible_config(DMA1, FLEX_CHANNEL1, DMA_FLEXIBLE_ADC1);

      dma_default_para_init(&dma_init_struct);
      dma_init_struct.buffer_size = 10;
      dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
      dma_init_struct.memory_base_addr = (uint32_t)adc1_ordinary_valuetab;
      dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD;
      dma_init_struct.memory_inc_enable = TRUE;
      dma_init_struct.peripheral_base_addr = (uint32_t)&(ADC1->odt);
      dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD;
      dma_init_struct.peripheral_inc_enable = FALSE;
      dma_init_struct.priority = DMA_PRIORITY_VERY_HIGH;
      dma_init_struct.loop_mode_enable = TRUE;
      dma_init(DMA1_CHANNEL1, &dma_init_struct);

      dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);
      dma_channel_enable(DMA1_CHANNEL1, TRUE);
}

/**
* @briefadc configuration.
* @paramnone
* @retval none
*/
static void Joy_adc_config(void)
{
      adc_base_config_type adc_base_struct;
      crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE);
      crm_adc_clock_div_set(CRM_ADC_DIV_6);

      adc_base_default_para_init(&adc_base_struct);
      adc_base_struct.sequence_mode = TRUE;
      adc_base_struct.repeat_mode = TRUE;
      adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT;
      adc_base_struct.ordinary_channel_length = 2;
      adc_base_config(ADC1, &adc_base_struct);
      adc_ordinary_channel_set(ADC1, ADC_CHANNEL_4, 1, ADC_SAMPLETIME_1_5);
      adc_ordinary_channel_set(ADC1, ADC_CHANNEL_5, 2, ADC_SAMPLETIME_1_5);
      adc_ordinary_conversion_trigger_set(ADC1, ADC12_ORDINARY_TRIG_SOFTWARE, TRUE);
      adc_dma_mode_enable(ADC1, TRUE);

      adc_enable(ADC1, TRUE);
      adc_calibration_init(ADC1);
      while(adc_calibration_init_status_get(ADC1));
      adc_calibration_start(ADC1);
      while(adc_calibration_status_get(ADC1));
}

/**
* @briefJoystick Initialization.
* @paramnone
* @retval none
*/
void Joystick_Init(void)
{      
      Joy_gpio_config();
      Joy_dma_config();
      Joy_adc_config();
      printf("software_trigger_repeat \r\n");
    adc_ordinary_software_trigger_enable(ADC1, TRUE);
    while(dma_trans_complete_flag == 0);
}

以下是XY轴数据处理与按键数据的处理,代码如下:
void Joystick_Handle(void)
{

          adcval1=0;
          adcval2=0;
          for( jindex = 0; jindex < 5; jindex++)
          {
                adcval1+=adc1_ordinary_valuetab;
                adcval2+=adc1_ordinary_valuetab;
          }
         
          Xtemp=adcval1/5;
          Ytemp=adcval2/5;
//          printf("X=%d,Y=%d\r\n",Xtemp,Ytemp);

          X=((Xtemp-Xmin)*255)/(Xmax-Xmin);
          Y=((Ytemp-Ymin)*255)/(Ymax-Ymin);
          printf("X=%d,Y=%d\r\n",X,Y);
          report_buf=X;
          report_buf=Y;
          report_buf=(~gpio_input_data_read(GPIOB)&0xFF);
          if(usbd_connect_state_get(&otg_core_struct.dev) == USB_CONN_STATE_CONFIGURED)
          {
               custom_hid_class_send_report(&otg_core_struct.dev, report_buf, USBD_CUSTOM_IN_MAXPACKET_SIZE);
          }
         
      
}最后是main函数,如下


/**
* @briefmain function.
* @paramnone
* @retval none
*/
int main(void)
{
      
nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);

system_clock_config();

at32_board_init();
uart_print_init(115200);
Joystick_Init();
   /* usb gpio config */
usb_gpio_config();

#ifdef USB_LOW_POWER_WAKUP
usb_low_power_wakeup_config();
#endif

/* enable otgfs clock */
crm_periph_clock_enable(OTG_CLOCK, TRUE);

/* select usb 48m clcok source */
usb_clock48m_select(USB_CLK_HEXT);

/* enable otgfs irq */
nvic_irq_enable(OTG_IRQ, 0, 0);

/* init usb */
usbd_init(&otg_core_struct,
            USB_FULL_SPEED_CORE_ID,
            USB_ID,
            &custom_hid_class_handler,
            &custom_hid_desc_handler);

while(1)
{

      Joystick_Handle();

}
}

四、下载验证:如下图,成功枚举成一个XY轴,8个按键的usb joystick,经测试,串口数据已经改变,但usb上报的数据改变很慢,导致效果不佳,也可能是我配置不正确的问题;最后附赠开源代码;

由于up主水平有限,所以帖子中难免有出错和讲得不好的地方,欢迎各位观众提出意见和建议,谢谢!







页: [1]
查看完整版本: 【AT-START-F425测评】+ USB HID设备Joystick开发体验与外设ADC DMA...