Kjetil's Information Center: A Blog About My Projects

Joystick Mouse on GR-SAKURA

Here is another project based on the GR-SAKURA board. It translates joystick movement into mouse movement, so it can be used on a PC. This is done reading three analog inputs from the joystick and forwarding data over an UART using the simple Microsoft Serial Mouse format.

The software is based heavily on the 30JH joystick that I happen to have. This is a 3-axis joystick, and the last axis is used to simulate the button presses.

This command in Linux can be used to get it connected:

sudo inputattach -bare /dev/ttyUSB0
          


Here's a photo of the setup:

GR-SAKURA wth Joystick


Here is the main part of the code, which implements the serial mouse protocol:

#include "uart.h"
#include "adc.h"

/* Raw ADC reference values: */
#define JOYSTICK_POS_MAX 2464
#define JOYSTICK_POS_MIN 2080 /* JOYSTICK_POS_MAX - (128 * 3) */
#define JOYSTICK_CENTER  2048
#define JOYSTICK_NEG_MIN 2016 /* JOYSTICK_NEG_MAX + (128 * 3) */
#define JOYSTICK_NEG_MAX 1632

static unsigned char prev_buttons = 0;

static unsigned char convert_adc_to_move_value(short value)
{
  /* Scaling and manual conversion to two's complement. */
  if (value > JOYSTICK_POS_MIN) {
    if (value > JOYSTICK_POS_MAX) {
      value = JOYSTICK_POS_MAX;
    }
    return (value - (JOYSTICK_POS_MIN + 1)) / 3;

  } else if (value < JOYSTICK_NEG_MIN) {
    if (value < JOYSTICK_NEG_MAX) {
      value = JOYSTICK_NEG_MAX;
    }
    return ((value - (JOYSTICK_NEG_MAX + 1)) / 3) + 128;

  } else {
    return 0; /* Filtered. */
  }
}

static unsigned char convert_adc_to_button_value(short value)
{
  if (value > JOYSTICK_POS_MIN) {
    return 0b10; /* Left button pressed. */

  } else if (value < JOYSTICK_NEG_MIN) {
    return 0b01; /* Right button pressed. */

  } else {
    return 0b00; /* No buttons pressed. */
  }
}

static short invert_adc_value(short value)
{
  if (value > JOYSTICK_CENTER) {
    return JOYSTICK_CENTER - (value - JOYSTICK_CENTER);
  } else {
    return JOYSTICK_CENTER + (JOYSTICK_CENTER - value);
  } 
}

static int mouse_format(short x_move_adc, short y_move_adc,
                        short button_adc, unsigned char *data)
{
  unsigned char x_move, y_move, buttons;

  x_move = convert_adc_to_move_value(x_move_adc);
  y_move = convert_adc_to_move_value(invert_adc_value(y_move_adc));
  buttons = convert_adc_to_button_value(button_adc);

  data[0] = 0b11000000;
  data[1] = 0b10000000;
  data[2] = 0b10000000;

  data[0] |= (buttons << 4);
  data[0] |= ((y_move >> 4) & 0b00001100);
  data[0] |= ((x_move >> 6) & 0b00000011);
  data[1] |= (x_move & 0b00111111);
  data[2] |= (y_move & 0b00111111);

  if (y_move > 0 || x_move > 0 || buttons != prev_buttons) {
    prev_buttons = buttons;
    return 1; /* Activity */
  } else {
    return 0; /* No activity */
  }
}

void mouse_loop(void)
{
  unsigned char data[3];

  while(1) {
    asm("wait");
    if (mouse_format(adc_get(0), adc_get(1), adc_get(2), data)) {
      uart0_send(data, 3);
    }
  }
}
          


Get the complete code under the MIT License here, which requires the RX GCC toolchain to compile.

Topic: Open Source, by Kjetil @ 12/12-2018, Article Link