Skip to content

Contributed by bzhou830, organized by Ai-Thinker

[Peripheral Porting] Ai-WB2+Dual-Axis Joystick Module

Peripheral introduction

The dual-axis joystick module uses the metal-button joystick potentiometer from PS2 game controllers. The module provides two analog output interfaces and one digital output interface. The output values correspond to the x- and y-axis offsets, which are analog values. The button indicates whether the user has pressed down on the z-axis, and its output is a digital switch value.

The module interfaces are as follows:

Porting process

Based on the analysis above, we need:

  1. Two ADC channels to sample the analog values of the x-axis and y-axis respectively;
  2. One GPIO input to detect the digital output on the z-axis;

In summary, we need to use the ADC and GPIO input functions.

Note that the ADC usage mentioned above only uses one channel, but here we need to use two channels simultaneously, so we need to check the documentation for the corresponding API calls. Looking through the documentation, we can find:

Click to expand full code
html
int hosal_adc_add_channel(hosal_adc_dev_t *adc,uint32_t channel)

Add an ADC channel to the ADC device. The parameters are as follows:

  • adc: the ADC port device
  • channel: the ADC channel to add
  • Return value: returns 0 on success, otherwise EIO or another value

With this, we can add multiple ADC sampling channels.

Hardware wiring

For the hardware connection, the left side is the WB2 and the right side is the dual-axis joystick.

IO11 ---> VRX

IO5 ---> VRY

IO3 ---> SW

3V3 ---> 5V

GND ---> GND

Code analysis

Click to expand full code
c
#include <stdio.h>

#include <string.h>

#include <FreeRTOS.h>

#include <task.h>

#include <hosal_adc.h>

#include <hosal_gpio.h>

#include <bl_adc.h>

#include <bl_gpio.h>

#include <blog.h>

/**********   BL602 ADC ************
*    channel0   ----->     gpio12
*    channel1   ----->     gpio4
*    channel2   ----->     gpio14
*    channel3   ----->     gpio13
*    channel4   ----->     gpio5
*    channel5   ----->     gpio6
*    channel7   ----->     gpio9
*    channel9   ----->     gpio10
*    channel10  ----->     gpio11
*    channel11  ----->     gpio15
*/

#define ADC_X_PIN           11
#define ADC_Y_PIN           5
#define KEY_PIN             3

void main(void)
{
    static uint8_t key_state = 0;
    static hosal_gpio_dev_t key;
    key.port = KEY_PIN;
    key.config = INPUT_PULL_UP;
    hosal_gpio_init(&key);

    static hosal_adc_dev_t adc0 = {
        .cb = NULL,
        .config = {
            .mode = HOSAL_ADC_ONE_SHOT,
            .pin = ADC_X_PIN,
            .sampling_freq = 340,
        },
        .dma_chan = 0,
        .p_arg = NULL,
        .port = 0,
    };

    hosal_adc_init(&adc0);

    hosal_adc_add_channel(&adc0, bl_adc_get_channel_by_gpio(ADC_X_PIN));
    hosal_adc_add_channel(&adc0, bl_adc_get_channel_by_gpio(ADC_Y_PIN));

    for (;;)
    {
        int v_y = hosal_adc_value_get(&adc0, bl_adc_get_channel_by_gpio(ADC_Y_PIN), 100);
        int v_x = hosal_adc_value_get(&adc0, bl_adc_get_channel_by_gpio(ADC_X_PIN), 100);
        hosal_gpio_input_get(&key, &key_state);

        blog_info("x = %ld mV, y = %ld mV, btn = %d\r\n", v_y, v_x, key_state);

        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

Result verification

Released under the MIT License. Build Time 2026-09-11 14:52:23