errors when HID_CONTROLS enabled for app_usb_aud_xk_316_mc

Discussions about USB Audio on XMOS devices
usb2.0
Junior Member
Posts: 4
Joined: Sat Dec 16, 2023 11:44 pm

errors when HID_CONTROLS enabled for app_usb_aud_xk_316_mc

Post by usb2.0 »

Hi,

I am trying to implement HID controls on the multichannel audio board XK-AUDIO-316-MC-AB. I want to use the 3 onboard pushbuttons for play/pause and skip track, back track functionality. I am using sw_usb_audio library version 7.3.1 and the XTC tools 15.2.1

Using xtc tools 15.2.1 command prompt, I have no issues building and flashing the example code found in xmos_usb_audio\sw_usb_audio\app_usb_aud_xk_316_mc\bin\2AMi2o2xxxxxx if I don't change anything in the code.

However, I get a compilation error when I enable HID_CONTROLS in the file C:\xmos_usb_audio\sw_usb_audio\app_usb_aud_xk_316_mc\src\core\xua_conf.h

Code: Select all

/* Enable/Disable example HID code - Default is off */
#ifndef HID_CONTROLS
#define HID_CONTROLS       (1)
#endif
And this is the error:

Code: Select all

Rebuild .build_2AMi2o2xxxxxx/_obj.rsp
Creating app_usb_aud_xk_316_mc.xe
C:/xmos_usb_audio/lib_xua/lib_xua/src/core/buffer/ep/ep_buffer.xc: Error: Undefined reference to 'UserHIDGetData'
C:/xmos_usb_audio/lib_xua/lib_xua/src/core/buffer/ep/ep_buffer.xc: Error: Undefined reference to 'UserHIDInit'
xmake[1]: *** [bin/2AMi2o2xxxxxx/app_usb_aud_xk_316_mc.xe] Error 1
xmake: *** [bin/2AMi2o2xxxxxx/app_usb_aud_xk_316_mc.xe] Error 2
I copied the file hid_report_descriptor.h from the folder
xmos_usb_audio\sw_usb_audio\app_usb_aud_xk_216_mc\src\
into the src folder in my project

And I found the 2 missing functions in the hidbuttons.xc file in the extensions folder of the same 216_mc project, but copying that file to the extensions directory of my project does not resolve the error. What am I doing wrong?

Thanks


usb2.0
Junior Member
Posts: 4
Joined: Sat Dec 16, 2023 11:44 pm

Post by usb2.0 »

It seems I have to also define XUA_HID_ENABLED

Code: Select all

#ifndef XUA_HID_ENABLED
#define XUA_HID_ENABLED       (1)
#endif
And the functions UserHIDGetData() and UserHIDInit() are still not defined in the file ep_buffer.xc
The prototypes are in user_hid.h but the function definitions are in hidbuttons.xc and they are not being found by the linker. How do I make .xc files link?

It links if I add the xc file to the module_build_info file in lib_xua/lib_xua

Code: Select all

XCC_FLAGS_user_hid.xc = $(MODULE_XCC_FLAGS) -Os -mno-dual-issue
Last edited by usb2.0 on Mon Jan 01, 2024 10:12 pm, edited 1 time in total.
usb2.0
Junior Member
Posts: 4
Joined: Sat Dec 16, 2023 11:44 pm

Post by usb2.0 »

I can compile and run the code on the 316_mc dev kit. I successfully got the 3 onboard LEDs to toggle when I press the 3 push buttons. But the the basic HID functionality is not working. When, I connect the USB port to my PC, it makes the sound like a new device got plugged in, but it is not showing in device manager and it does not pop up as a USB audio device in Windows. I seem to be stuck in the while(1) loop in UserHIDPoll()

Here is my code for user_hid.xc:

Code: Select all

#include <xs1.h>
#include <platform.h>

#include "xua_conf.h"
#include "user_hid.h"
#include "xua_hid_report.h"

on tile[0]: out port db_leds = XS1_PORT_4F;

#if HID_CONTROLS > 0
in port p_sw = on tile[XUD_TILE] : XS1_PORT_4E;   

#define P_GPI_BUTA_SHIFT        0x00
#define P_GPI_BUTA_MASK         (1<<P_GPI_BUTA_SHIFT)
#define P_GPI_BUTB_SHIFT        0x01
#define P_GPI_BUTB_MASK         (1<<P_GPI_BUTB_SHIFT)
#define P_GPI_BUTC_SHIFT        0x02
#define P_GPI_BUTC_MASK         (1<<P_GPI_BUTC_SHIFT)

/* Write HID Report Data into hidData array
 *
 * Bits are as follows:
 * 0: Play/Pause
 * 1: Scan Next Track
 * 2: Scan Prev Track
 * 3: Volume Up
 * 4: Volume Down
 * 5: Mute
 */

unsigned multicontrol_count = 0;
unsigned wait_counter = 0;


#define THRESH 1
#define MULTIPRESS_WAIT_MS 200
#define HIDBUTTONS_POLL_MS   1

#define HID_CONTROL_PLAYPAUSE   0x01
#define HID_CONTROL_NEXT        0x02
#define HID_CONTROL_PREV        0x04
#define HID_CONTROL_VOLUP       0x08
#define HID_CONTROL_VOLDN       0x10
#define HID_CONTROL_MUTE        0x20

typedef enum
{
	STATE_IDLE = 0x00,
	STATE_PLAY = 0x01,
	STATE_NEXTPREV = 0x02,
}t_controlState;

t_controlState state;

unsigned lastA;

static unsigned char lastHidData;

void UserHIDPoll()
{         
    state = STATE_IDLE;
    unsigned char hidData = 0;
    db_leds <: 0xF; // all 4 leds on  

    while (1) {        
        delay_milliseconds(HIDBUTTONS_POLL_MS);               

        if (hidIsChangePending(0)) {            
            continue;
        }

        // Variables for buttons a, b, c
        unsigned a, b, c, tmp;

        p_sw :> tmp;

        // Buttons are active low
        tmp = ~tmp;

        a = (tmp & (P_GPI_BUTA_MASK))>>P_GPI_BUTA_SHIFT;
        b = (tmp & (P_GPI_BUTB_MASK))>>P_GPI_BUTB_SHIFT;
        c = (tmp & (P_GPI_BUTC_MASK))>>P_GPI_BUTC_SHIFT;  

        if(a) {
            db_leds <: 0xE; // led 0 off
        }   
        if(b) {
            db_leds <: 0xD; // led 1 off
        }
        if(c) {
            db_leds <: 0xB; // led 2 off          
        }
    
        hidData = 0;

        if(1)
        {
            // Assign buttons A and B to Vol Down/Up 
            hidData |= a * HID_CONTROL_VOLDN;
            hidData |= b * HID_CONTROL_VOLUP;
            hidData |= c * HID_CONTROL_MUTE;            
        }
        else
        {
            // Assign buttons A and B to play for single tap, next/prev for double tap
            if(b)
            {
                multicontrol_count++;
                wait_counter = 0;
                lastA = 0;
            }
            else if(a)
            {
                multicontrol_count++;
                wait_counter = 0;
                lastA = 1;
            }
            else
            {
                if(multicontrol_count > THRESH)
                {
                    state++;
                }

                wait_counter++;

                if(wait_counter > (MULTIPRESS_WAIT_MS / HIDBUTTONS_POLL_MS))
                {
                    if(state == STATE_PLAY)
                    {
                        hidData = HID_CONTROL_PLAYPAUSE;
                    }
                    else if(state == STATE_NEXTPREV)
                    {
                        if(lastA)
                            hidData = HID_CONTROL_PREV;
                        else
                            hidData = HID_CONTROL_NEXT;
                    }
                    state = STATE_IDLE;
                }
                db_leds <: 0x0; // leds off 
                multicontrol_count = 0;
            }
        }

        if (hidData == lastHidData) {            
            continue;
        }

        unsafe {
            volatile unsigned char * unsafe lastHidDataUnsafe = &lastHidData;
            *lastHidDataUnsafe = hidData;
            hidSetChangePending(0);
        }    
    }
}

size_t UserHIDGetData( const unsigned id, unsigned char hidData[ HID_MAX_DATA_BYTES ])
{         
    db_leds <: 0x7; // led 3 off
    // There is only one report, so the id parameter is ignored    
    hidData[0] = lastHidData;

    // One byte of data is always returned
    return 1;
}

void UserHIDInit( void )
{
    UserHIDPoll();
}

#endif  // HID_CONTROLS > 0
I can tell the UserHIDGetData() function never runs. Does anyone know how the endpoint 0 gets notified that the HID data state has changed?

If anyone can help that would be great, I can't find any documentation on this. The only HID example in the lib_xud folder uses AN00129 which is from 2016 and does not seem to be relevant to the new tools. That example says to make a task in main for handling the HID.

In the lib_xua folder, main.xc doesn't have a task for handling HID, it just says this:

Code: Select all

#if (XUA_HID_ENABLED)
                           , c_xud_in[ENDPOINT_NUMBER_IN_HID]
#endif
User avatar
fabriceo
XCore Addict
Posts: 186
Joined: Mon Jan 08, 2018 4:14 pm

Post by fabriceo »

Hi, I cannot help you directly with the HID interaction, just to mention that lib_xua integrates the management of the HID endpoint within the "buffer" task, so you don't need a specific task for managing the USB HID interface.
usb2.0
Junior Member
Posts: 4
Joined: Sat Dec 16, 2023 11:44 pm

Post by usb2.0 »

fabriceo wrote: Tue Jan 02, 2024 9:26 pm Hi, I cannot help you directly with the HID interaction, just to mention that lib_xua integrates the management of the HID endpoint within the "buffer" task, so you don't need a specific task for managing the USB HID interface.
Hello,
Thank you. Your hint helped me! I was calling the UserHIDPoll() function from the HID init function like this:

Code: Select all

void UserHIDInit( void )
{
    UserHIDPoll();
}
Clearly the program is stalling in this polling function. So I instead add it as a parallel task in main.xc within the lib_xua folder

Code: Select all

#if (XUA_HID_ENABLED)
    on stdcore[0]: UserHIDPoll();
#endif
Not sure if that is the preferred way but now the xmos enumerates as a USB audio device and a HID device and the buttons are currently working as volume up/down mute. The double press works for previous/next so I will just refactor that code to make simple single press do previous/next and toggle play/pause like I wanted.