Volume Control not working

General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
Post Reply
ripper121
Posts: 8
Joined: Sat Aug 16, 2014 11:48 am

Volume Control not working

Post by ripper121 » Tue Aug 22, 2017 10:00 am

Hello :),

i dont get the Volume controle running :(.

This is my usb Hid Report Descriptor:

Code: Select all

#define USB_CFG_INTERFACE_CLASS     0x03    /* HID class */
#define USB_CFG_INTERFACE_SUBCLASS  0x01    /* Boot-device subclass */
#define USB_CFG_INTERFACE_PROTOCOL  0x01    /* Keyboard protocol */

#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH    35

const PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {   /* USB report descriptor */
   0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
   0x09, 0x06,                    // USAGE (Keyboard)
   0xa1, 0x01,                    // COLLECTION (Application)
   0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
   0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
   0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
   0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
   0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
   0x75, 0x01,                    //   REPORT_SIZE (1)
   0x95, 0x08,                    //   REPORT_COUNT (8)
   0x81, 0x02,                    //   INPUT (Data,Var,Abs)
   0x95, 0x01,                    //   REPORT_COUNT (1)
   0x75, 0x08,                    //   REPORT_SIZE (8)
   0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)
   0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
   0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
   0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
   0xc0                           // END_COLLECTION
};

#define KEY_VOLUME_UP         0x80     // Keyboard Volume Up 0xE9
#define KEY_VOLUME_DOWN       0x81     // Keyboard Volume Down 0xEA



This is the complete code:

Code: Select all

#define F_CPU 12000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
#include "usbdrv/usbdrv.h"

/* ----------------------- hardware I/O abstraction ------------------------ */

/* pin assignments:
LED1 = PC1
LED2 = PC0

COL1 = PC2
COL2 = PC3
COL3 = PC4
COL4 = PC5

ROW1 = PD0
ROW2 = PD1

PB1   USB-
PB0   USB+ (int0)
*/

static void resetMatrix(void)
{
   //Key Matrix
   //COLS
   DDRC &= ~(1 << PC2);//Input
   PORTC &= ~(1 << PC2);//Low
   DDRC &= ~(1 << PC3);//Input
   PORTC &= ~(1 << PC3);//Low
   DDRC &= ~(1 << PC4);//Input
   PORTC &= ~(1 << PC4);//Low
   DDRC &= ~(1 << PC5);//Input
   PORTC &= ~(1 << PC5);//Low
   //ROWS
   DDRD &= ~(1 << PD0);//Input
   PORTD &= ~(1 << PD0);//Low
   DDRD &= ~(1 << PD1);//Input
   PORTD &= ~(1 << PD1);//Low
}

static void hardwareInit(void)
{
   uchar   i, j;
   j = 0;
   while(--j){     /* USB Reset by device only required on Watchdog Reset */
      i = 0;
      while(--i); /* delay >10ms for USB reset */
   }
   /* configure timer 0 for a rate of 12M/(1024 * 256) = 45.78 Hz (~22ms) */
   TCCR0 = 5;      /* timer 0 prescaler: 1024 */
   
   //Led
   DDRC |= (1 << PC0); // Output
   PORTC &= ~(1 << PC0);  //PC0 LOW
   DDRC |= (1 << PC1); // Output
   PORTC &= ~(1 << PC1);  //PC1 LOW
   
   resetMatrix();
}

/* ------------------------------------------------------------------------- */

/* The following function returns an index for the first key pressed. It
* returns 0 if no key is pressed.
*/
static uchar    keyPressed(void)
{
   resetMatrix();
   //ROW1 OUTPUT
   DDRD |= (1 << PD0);
   //ROW1 HIGH
   PORTD |= (1 << PD0);
   //ROW2 OUTPUT
   DDRD |= (1 << PD1);
   //ROW2 LOW
   PORTD &= ~(1 << PD1);
   
   //COL1 Input DOWN && PLUS
   DDRC &= ~(1 << PC2);
   PORTC |= (1 << PC2);
   DDRC &= ~(1 << PC4);
   PORTC |= (1 << PC4);
   if (!(PINC & (1<<PC2)) && !(PINC & (1<<PC4))) {
      return 10;
   }
   
   //COL1 Input DOWN && MINUS
   DDRC &= ~(1 << PC2);
   PORTC |= (1 << PC2);
   DDRC &= ~(1 << PC5);
   PORTC |= (1 << PC5);
   if (!(PINC & (1<<PC2)) && !(PINC & (1<<PC5))) {
      return 9;
   }
   
   resetMatrix();
   
   //ROW1 OUTPUT
   DDRD |= (1 << PD0);
   //ROW1 LOW
   PORTD &= ~(1 << PD0);
   
   //ROW2 OUTPUT
   DDRD |= (1 << PD1);
   //ROW2 HIGH
   PORTD |= (1 << PD1);
   
   //COL1 Input LEFT
   DDRC &= ~(1 << PC2);
   PORTC |= (1 << PC2);
   if (!(PINC & (1<<PC2))) {
      return 6;
   }
   
   //COL2 Input UP
   DDRC &= ~(1 << PC3);
   PORTC |= (1 << PC3);
   if (!(PINC & (1<<PC3))) {
      return 7;
   }
   
   //COL3 Input FAV
   DDRC &= ~(1 << PC4);
   PORTC |= (1 << PC4);
   if (!(PINC & (1<<PC4))) {
      return 1;
   }
   
   //COL4 Input F5
   DDRC &= ~(1 << PC5);
   PORTC |= (1 << PC5);
   if (!(PINC & (1<<PC5))) {
      return 8;
   }
   
   resetMatrix();
   
   //ROW1 OUTPUT
   DDRD |= (1 << PD0);
   //ROW1 HIGH
   PORTD |= (1 << PD0);
   
   
   //ROW2 OUTPUT
   DDRD |= (1 << PD1);
   //ROW2 LOW
   PORTD &= ~(1 << PD1);
   
   //COL1 Input DOWN
   DDRC &= ~(1 << PC2);
   PORTC |= (1 << PC2);
   if (!(PINC & (1<<PC2))) {
      return 2;
   }
   
   //COL2 Input RIGHT
   DDRC &= ~(1 << PC3);
   PORTC |= (1 << PC3);
   if (!(PINC & (1<<PC3))) {
      return 5;
   }
   
   //COL3 Input PLUS
   DDRC &= ~(1 << PC4);
   PORTC |= (1 << PC4);
   if (!(PINC & (1<<PC4))) {
      return 4; //3
   }
   
   //COL4 Input MINUS
   DDRC &= ~(1 << PC5);
   PORTC |= (1 << PC5);
   if (!(PINC & (1<<PC5))) {
      return 3; //4
   }
   
   
   return 0;

}

/* ------------------------------------------------------------------------- */
/* ----------------------------- USB interface ----------------------------- */
/* ------------------------------------------------------------------------- */

static uchar    reportBuffer[2];    /* buffer for HID reports */
static uchar    idleRate;           /* in 4 ms units */

const PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {   /* USB report descriptor */
   0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
   0x09, 0x06,                    // USAGE (Keyboard)
   0xa1, 0x01,                    // COLLECTION (Application)
   0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
   0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
   0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
   0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
   0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
   0x75, 0x01,                    //   REPORT_SIZE (1)
   0x95, 0x08,                    //   REPORT_COUNT (8)
   0x81, 0x02,                    //   INPUT (Data,Var,Abs)
   0x95, 0x01,                    //   REPORT_COUNT (1)
   0x75, 0x08,                    //   REPORT_SIZE (8)
   0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)
   0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
   0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
   0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
   0xc0                           // END_COLLECTION
};
/* We use a simplifed keyboard report descriptor which does not support the
* boot protocol. We don't allow setting status LEDs and we only allow one
* simultaneous key press (except modifiers). We can therefore use short
* 2 byte input reports.
* The report descriptor has been created with usb.org's "HID Descriptor Tool"
* which can be downloaded from http://www.usb.org/developers/hidpage/.
* Redundant entries (such as LOGICAL_MINIMUM and USAGE_PAGE) have been omitted
* for the second INPUT item.
*/
enum keycodes {
   KEY__ = 0,
   KEY_errorRollOver,
   KEY_POSTfail,
   KEY_errorUndefined,
   KEY_A,        // 4
   KEY_B,
   KEY_C,
   KEY_D,
   KEY_E,
   KEY_F,
   KEY_G,
   KEY_H,
   KEY_I,
   KEY_J,
   KEY_K,
   KEY_L,
   KEY_M,        // 0x10
   KEY_N,
   KEY_O,
   KEY_P,
   KEY_Q,
   KEY_R,
   KEY_S,
   KEY_T,
   KEY_U,
   KEY_V,
   KEY_W,
   KEY_X,
   KEY_Y,
   KEY_Z,
   KEY_1,
   KEY_2,
   KEY_3,        // 0x20
   KEY_4,
   KEY_5,
   KEY_6,
   KEY_7,
   KEY_8,
   KEY_9,
   KEY_0,        // 0x27
   KEY_enter,
   KEY_esc,
   KEY_bckspc,   // backspace
   KEY_tab,
   KEY_spc,      // space
   KEY_minus,    // - (and _)
   KEY_equal,    // = (and +)
   KEY_lbr,      // [
   KEY_rbr,      // ]  -- 0x30
   KEY_bckslsh,  // \ (and |)
   KEY_hash,     // Non-US # and ~
   KEY_smcol,    // ; (and :)
   KEY_ping,     // ' and "
   KEY_grave,    // Grave accent and tilde
   KEY_comma,    // , (and <)
   KEY_dot,      // . (and >)
   KEY_slash,    // / (and ?)
   KEY_cpslck,   // capslock
   KEY_F1,
   KEY_F2,
   KEY_F3,
   KEY_F4,
   KEY_F5,
   KEY_F6,
   KEY_F7,       // 0x40
   KEY_F8,
   KEY_F9,
   KEY_F10,
   KEY_F11,
   KEY_F12,
   KEY_PrtScr,
   KEY_scrlck,
   KEY_break,
   KEY_ins,
   KEY_home,
   KEY_pgup,
   KEY_del,
   KEY_end,
   KEY_pgdn,
   KEY_rarr,
   KEY_larr,     // 0x50
   KEY_darr,
   KEY_uarr,
   KEY_numlock,
   KEY_KPslash,
   KEY_KPast,
   KEY_KPminus,
   KEY_KPplus,
   KEY_KPenter,
   KEY_KP1,
   KEY_KP2,
   KEY_KP3,
   KEY_KP4,
   KEY_KP5,
   KEY_KP6,
   KEY_KP7,
   KEY_KP8,      // 0x60
   KEY_KP9,
   KEY_KP0,
   KEY_KPcomma,
   KEY_Euro2,

   /* These are NOT standard USB HID - handled specially in decoding,
   so they will be mapped to the modifier byte in the USB report */
   KEY_Modifiers,
   MOD_LCTRL,    // 0x01
   MOD_LSHIFT,   // 0x02
   MOD_LALT,     // 0x04
   MOD_LGUI,     // 0x08
   MOD_RCTRL,    // 0x10
   MOD_RSHIFT,   // 0x20
   MOD_RALT,     // 0x40
   MOD_RGUI,     // 0x80
};

#define KEY_VOLUME_UP         0x80     // Keyboard Volume Up 0xE9
#define KEY_VOLUME_DOWN       0x81     // Keyboard Volume Down 0xEA

#define NUM_KEYS    10
static const uchar  keyReport[NUM_KEYS + 1][2] PROGMEM = {
   /* none */{ 0 },                   /* no key pressed */
   /*  1 */{ 0, KEY_F },
   /*  2 */{ 0, KEY_darr },
   /*  3 */{ 0, KEY_KPplus },
   /*  4 */{ 0, KEY_KPminus },
   /*  5 */{ 0, KEY_rarr },
   /*  6 */{ 0, KEY_larr },
   /*  7 */{ 0, KEY_uarr },
   /*  8 */{ 0, KEY_F5 },
   /*  9 */{ 0, KEY_VOLUME_UP },
   /*  10 */{ 0, KEY_VOLUME_DOWN },
};


static void buildReport(uchar key)
{
   /* This (not so elegant) cast saves us 10 bytes of program memory */
   *(int *)reportBuffer = pgm_read_word(keyReport[key]);
}

uchar   usbFunctionSetup(uchar data[8])
{
   usbRequest_t    *rq = (void *)data;

   usbMsgPtr = reportBuffer;
   if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){    /* class request type */
      if(rq->bRequest == USBRQ_HID_GET_REPORT){  /* wValue: ReportType (highbyte), ReportID (lowbyte) */
         /* we only have one report type, so don't look at wValue */
         buildReport(keyPressed());
         return sizeof(reportBuffer);
         }else if(rq->bRequest == USBRQ_HID_GET_IDLE){
         usbMsgPtr = &idleRate;
         return 1;
         }else if(rq->bRequest == USBRQ_HID_SET_IDLE){
         idleRate = rq->wValue.bytes[1];
      }
      }else{
      /* no vendor specific requests implemented */
   }
   return 0;
}




/* ------------------------------------------------------------------------- */
int   main(void)
{   
   uchar   key, lastKey = 0, keyDidChange = 0;
   uchar   idleCounter = 0;

   wdt_enable(WDTO_2S);
   hardwareInit();
   usbInit();
   sei();
   for(;;){   /* main event loop */
      wdt_reset();
      usbPoll();
      key = keyPressed();
      if(lastKey != key){
         lastKey = key;
         keyDidChange = 1;
      }
      if(TIFR & (1<<TOV0)){   /* 22 ms timer */
         TIFR = 1<<TOV0;
         if(idleRate != 0){
            if(idleCounter > 40){
               idleCounter -= 1;   /* 22 ms in units of 4 ms */
               }else{
               idleCounter = idleRate;
               keyDidChange = 1;
            }
         }
      }
      if(keyDidChange && usbInterruptIsReady()){
         keyDidChange = 0;
         /* use last key and not current key status in order to avoid lost
         changes in key status. */
         buildReport(lastKey);
         usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
      }
   }
   return 0;
   
   
   
   /*

   uchar   key, lastKey = 0, keyDidChange = 0;
   uint16_t delaytime = 2, delaytimer = 0;

   wdt_enable(WDTO_2S);
   hardwareInit();
   usbInit();
   sei();

   while (1){

   wdt_reset();
   usbPoll();

   if (usbInterruptIsReady()){
   buildReport(keyscan());
   usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
   }

   }

   return 0;
   */
}

/* ------------------------------------------------------------------------- */

ripper121
Posts: 8
Joined: Sat Aug 16, 2014 11:48 am

Re: Volume Control not working

Post by ripper121 » Tue Aug 22, 2017 2:49 pm

Found a solution:
I used the Tinker code from adafruit:

Here my new working FW:
https://github.com/ripper121/Keyboard/t ... r/Firmware

Post Reply