本帖最后由 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输入的初始化配置;
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] joystick gpio configuration.
* @param none
* @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);
}
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] dma configuration.
* @param none
* @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);
}
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] adc configuration.
* @param none
* @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));
}
/**
* @brief Joystick Initialization.
* @param none
* @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[jindex][0];
adcval2+=adc1_ordinary_valuetab[jindex][1];
}
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[0]=X;
report_buf[1]=Y;
report_buf[2]=(~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函数,如下
/**
* @brief main function.
* @param none
* @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主水平有限,所以帖子中难免有出错和讲得不好的地方,欢迎各位观众提出意见和建议,谢谢!
|