Arduino Joystick Shield Example

This example shows how to use the Sparkfun Joystick on the board. The Joystick shield contains an analog joystick which is connected to A0 and A1 analog channels of the Arduino connector. It also contains four push buttons connected at D3-D6 pins of the Arduino connector.

For this notebook, an Arduino joystick shield is required.


In [1]:
from pynq.overlays.base import BaseOverlay

base = BaseOverlay("base.bit")


1. Use Microblaze to control the joystick

Make sure the joystick shield is plugged in. For the Microblaze to transfer direction or button values back, we need to define a few additional constants.


In [2]:
DIRECTION_VALUE_MAP = {
    0: 'up',
    1: 'up_right',
    2: 'right',
    3: 'down_right',
    4: 'down',
    5: 'down_left',
    6: 'left',
    7: 'up_left',
    8: 'center'
}

BUTTON_INDEX_MAP = {
    'D3': 0,
    'D4': 1,
    'D5': 2,
    'D6': 3
}

The joystick can measure horizontal direction x and vertical direction y.

The thresholds for raw values are:

Horizontal:

Threshold Direction
x < 25000 left
25000 < x < 39000 center
x > 39000 right

Vertical:

Threshold Direction
y < 25000 down
25000 < y < 39000 center
y > 39000 up

In [3]:
%%microblaze base.ARDUINO

#include "xparameters.h"
#include "circular_buffer.h"
#include "gpio.h"
#include "xsysmon.h"
#include <pyprintf.h>

#define X_THRESHOLD_LOW 25000
#define X_THRESHOLD_HIGH 39000  

#define Y_THRESHOLD_LOW 25000
#define Y_THRESHOLD_HIGH 39000

typedef enum directions {
up = 0, 
right_up, 
right, 
right_down, 
down, 
left_down, 
left, 
left_up,
centered
}direction_e;

static gpio gpio_buttons[4];
static XSysMon SysMonInst;
XSysMon_Config *SysMonConfigPtr;
XSysMon *SysMonInstPtr = &SysMonInst;

int init_joystick(){
    unsigned int i, status;
    SysMonConfigPtr = XSysMon_LookupConfig(XPAR_SYSMON_0_DEVICE_ID);
    if(SysMonConfigPtr == NULL)
        return -1;
    status = XSysMon_CfgInitialize(
        SysMonInstPtr, SysMonConfigPtr, SysMonConfigPtr->BaseAddress);
    if(XST_SUCCESS != status)
        return -1;

    for (i=0; i<4; i++){
        gpio_buttons[i] = gpio_open(i+3);
        gpio_set_direction(gpio_buttons[i], GPIO_IN);
    }
    return 0;
}

unsigned int get_direction_value(){
    direction_e direction;
    unsigned int x_position, y_position;
    while ((XSysMon_GetStatus(SysMonInstPtr) & 
            XSM_SR_EOS_MASK) != XSM_SR_EOS_MASK);
    x_position = XSysMon_GetAdcData(SysMonInstPtr, XSM_CH_AUX_MIN+1);
    y_position = XSysMon_GetAdcData(SysMonInstPtr, XSM_CH_AUX_MIN+9);

    if (x_position > X_THRESHOLD_HIGH) {
        if (y_position > Y_THRESHOLD_HIGH) {
            direction = right_up;
        } else if (y_position < Y_THRESHOLD_LOW) {
            direction = right_down;
        } else {
            direction = right;
        }
    } else if (x_position < X_THRESHOLD_LOW) {
        if (y_position > Y_THRESHOLD_HIGH) {
            direction = left_up;
        } else if (y_position < Y_THRESHOLD_LOW) {
            direction = left_down;
        } else {
            direction = left;
        }
    } else {
        if (y_position > Y_THRESHOLD_HIGH) {
            direction = up;
        } else if (y_position < Y_THRESHOLD_LOW) {
            direction = down;
        } else {
            direction = centered;
        }
    }
    return direction;
}

unsigned int get_button_value(unsigned int btn_i){
    unsigned int value;
    value = gpio_read(gpio_buttons[btn_i]);
    return value;
}

2. Define Python wrapper for Microblaze functions

We will also need to initialize the joystick before we can read any value. The following function returns 0 if the initialization is successful.


In [4]:
init_joystick()


Out[4]:
0

The following Python wrappers will call the Microblaze functions internally.


In [5]:
def read_direction():
    direction_value = get_direction_value()
    return DIRECTION_VALUE_MAP[direction_value]

def read_button(button):
    return get_button_value(BUTTON_INDEX_MAP[button])

3. Find direction

We can measure the direction by calling read_direction().

For the next cell, leave the joystick in its natural position.


In [6]:
read_direction()


Out[6]:
'center'

Let's pull the joystick towards the bottom right corner.


In [7]:
read_direction()


Out[7]:
'down_right'

4. Read button values

Based on the schematic of the shield, we can see the read value will go low if the corresponding button has been pressed.

Run the next cell while pushing both button D4 and D6.


In [8]:
for button in BUTTON_INDEX_MAP:
    if read_button(button):
        print('Button {} is not pressed.'.format(button))
    else:
        print('Button {} is pressed.'.format(button))


Button D3 is not pressed.
Button D4 is pressed.
Button D5 is not pressed.
Button D6 is pressed.