PDA

View Full Version : MIDI over USB



RuudNL
- 10th November 2017, 11:53
Hello,
I would like to try to do this, but I don't know if this is possible...

I would like to behave a PIC based circuit as an (USB) MIDI (receiver) interface.
In the past I have managed to create circuits with a PIC that behaved like a HID device, that didn't need any drivers.
The point of this is, that most software applications need to 'see' a MIDI port, in order to send information to that port.
I suppose I have to change some values in the USB descriptors, but I have no idea where to start.
Most commercial USB to MIDI interfaces don't need a driver, so I suppose this must be possible.
Maybe somebody has experimented with this, and is willing to share some code with me?
Many thanks in advance!

(Just to be clear: I only need communication FROM the PC to the PIC circuit.)

Demon
- 10th November 2017, 19:07
Have you seen this?

http://www.microchip.com/forums/m409051.aspx

Edit: or this:
https://www.youtube.com/watch?v=thMxxFt8a0I

EDIT again: Or maybe this:
https://forum.sparkfun.com/viewtopic.php?t=17172

Robert

RuudNL
- 10th November 2017, 20:08
Nice, but not really PicBasic related.
(Also some of the links don't work.)

DaveC3
- 11th November 2017, 13:14
I did a USB Midi back in 2009, Here is the code. It has been too long ago for me to remember the specifics. Maybe it will help you get started.


' ************************************************** **********
' * Auto generated EasyHID file. PBP 2.60 and above *
' ************************************************** **********

' include the HID descriptor
INCLUDE "DESCUSB_MIDI.bas"
DEFINE WRITE_INT 1
Define LOADER_USED 1
DEFINE RESET_ORG 800h ' For Microchip USB Bootloader
DEFINE INTERRUPT_ORG 808h ' For Microchip USB Bootloader

DEFINE OSC 48 ' tell program we are using a 20mhz oscillator
DEFINE HSER_RCSTA 90h ' enable serial receive
DEFINE HSER_TXSTA 24h ' enable serial transmit
DEFINE HSER_BAUD 31250 ' set baud rate for MIDI transmission
DEFINE ADC_BITS 8 ' set the number of bits in the sample
DEFINE ADC_SAMPLEUS 50 ' set the sample time
I2C_Data var PORTD.1
I2C_CLK var PORTD.0


USBBufferSizeMax CON 16 ' maximum buffer size
USBBufferSizeTX CON 16 ' input
USBBufferSizeRX CON 16 ' output

' the USB buffer...
USBBuffer VAR BYTE[USBBufferSizeMax]
USBBufferCount VAR BYTE


Portb = %11111111
ADCON1 = %00000101 ' AN0 - AN9 analog
TRISA = %00101111 ' Set PORTA to inputs
TRISB = %00001100
TRISC = %00000000
TRISD = %11110000
TRISE = %00000111 ' Porte 1,2 ,3 inputs,
CMCON = 7 'PortA Digital
INTCON2.7 = 0 'weak pullups portB = 0, disable = 1
PORTE.7 = 1 ' weak pullups portd enabled

'================================================= =====================================
' Port A Registers (8 Bit Mode)
IODIRA con $00 ' Direction Bit Control Reg
IOBITSA con %11111111 ' Direction Bit Settings Reg (0 = output, 1 = input)
IPOLA con $01 ' Interrupt Polarity Control Reg
GPINTENA con $02 'Interrupt Enable Reg
DEFVALA con $03
INTCONA con $04
IOCONA con $05 ' I/O Configuration Reg
IOCONSETA con %10111000 ' IOCON register setting
GPPUA con $06 ' Pull-Up Control Reg
INTFA con $07 ' Interrupt Flag Register
INTCAPA con $08
GPIOA con $09 ' General Purpose I/O
IOLATA con $0A ' Output Latch Reg

'Port B Registers (8 Bit Mode)
IODIRB con $10 ' Port B Direction Bit Control Address
IOBITSB con %00000000 ' Port B Direction Bit Settings (0 = output, 1 = input)
IPOLB con $11 ' Interrupt Polarity Control
GPINTENB con $12 ' Interrupt Enable Reg
DEFVALB con $13
INTCONB con $14
IOCONB con $15 ' I/O Configuration Reg
IOCONSETB con %10111000 ' IOCON register setting
GPPUB con $16 ' Pull-Up Control Reg
INTFB con $17 ' Interrupt Flag Register
INTPOLB con $18
GPIOB con $19 ' General Purpose I/O Reg
IOLATB con $1A ' Output Latch Reg

'================================================= =======================================
' Port A Reguisters (16 Bit Mode)
IODIRA16 con $00
IODIRB16 con $01
IOCONA16 con $0A
IOCONB16 con $0B
GPIOA16 con $12
GPIOB16 con $13
OLATA16 con $14
OLATB16 con $15

IO_EXP0WR con $40 ' MCP23017 Write
IO_EXP0RD con $40 ' MCP23017 Read
IO_DAT var byte ' MCP23017 Data read
IO_DAT_OLD var byte
IO_DATA var byte ' MCP23017 Data read
IO_DAT_OLDA var byte
IO_DATB var byte ' MCP23017 Data read
IO_DAT_OLDB var byte
Out_Dat var byte
Enc1 var byte
Enc1_Old var byte
Enc1_Mask con %00000011
Enc2 var byte
Enc2_Old var byte
Enc2_Mask con %00001100
Enc3 var byte
Enc3_Old var byte
Enc3_Mask con %00110000
Enc4 var byte
Enc4_Old var byte
Enc4_Mask con %11000000
EncTemp var byte
Enc1_val var byte
Enc2_val var byte
Enc3_val var byte
Enc4_val var byte

CPS1 var byte
CPS2 var byte
CPS3 var byte
CPS4 var byte
CPS5 var byte
CPS6 var byte

'================================================= ============================
' The control code assignments for the 6 switches
'================================================= ============================
CPS1_CC VAR BYTE ' con 30
CPS2_CC VAR BYTE ' con 31
CPS3_CC VAR BYTE ' con 66
CPS4_CC VAR BYTE ' con 41
CPS5_CC VAR BYTE ' con 42
CPS6_CC VAR BYTE ' con 43
'================================================= ============================
' The control code assignments for the 4 encoders
'================================================= ============================
CPENC1_CC VAR BYTE ' con 84
CPENC2_CC VAR BYTE ' con 76
CPENC3_CC VAR BYTE ' con 68
CPENC4_CC VAR BYTE ' con 80

' Flags
SW1_Flag var bit
CPS1_Flag var bit
CPS2_Flag var bit
CPS3_Flag var bit
CPS4_Flag var bit
CPS5_Flag var bit
CPS6_Flag var bit

sl_ADC var word[9]
sl_Old var byte[9]
Channel var byte
Control var byte
Value var byte
j var byte
C0 Var word
C1 Var word
EXP var word
EXP1 var byte
EXPOld var byte
EXP_CC var byte
volout Var byte
Channel = 176
Control = 0
Upper var byte
Lower VAR BYTE
Bass VAR BYTE
SwitchBank var byte
SwitchBank1 var byte
SwitchBankOld var byte
RSS var byte
RSSOld var byte
CounterA var Byte
RawData var Byte [16]
k var byte
i var byte
LED1 var PORTC.2

upper = 12
lower = 0 '9
bass = 0 '
PORTD = $FF
FOR j = 0 TO 15
READ j, USBBuffer[j]
NEXT j
CPS1_CC = USBBuffer[0]
CPS2_CC = USBBuffer[1]
CPS3_CC = USBBuffer[2]
CPS4_CC = USBBuffer[3]
CPS5_CC = USBBuffer[4]
CPS6_CC = USBBuffer[5]
CPENC1_CC = USBBuffer[6]
CPENC2_CC = USBBuffer[7]
CPENC3_CC = USBBuffer[8]
CPENC4_CC = USBBuffer[9]
PAUSE 500


gosub InitMPC23017
goto MainLoop 'jump over subs to main loop


' ************************************************** **********
' Start of Subs
' ************************************************** **********
' * receive data from the USB bus *
' ************************************************** **********
DoUSBIn:
USBBufferCount = USBBufferSizeRX ' RX buffer size
USBIN 1, USBBuffer, USBBufferCount, DoUSBIn ' read data, if available
RETURN

' ************************************************** **********
' * wait for USB interface to attach *
' ************************************************** **********
DoUSBOut:
USBBufferCount = USBBufferSizeTX ' TX buffer size
USBOUT 1, USBBuffer, USBBufferCount, DoUSBOut ' if bus available, transmit data
RETURN
' ************************************************** **********
' * USB Attach detach *
' ************************************************** **********
Program:
led1 = 1
INCLUDE "USB_ASM_Service.pbp"
PAUSE 500
GOSUB DoUSBIn


FOR k = 0 TO 15
READ k , USBBuffer[k]
NEXT k
PAUSE 250
GOSUB DoUSBOut
PAUSE 250
GOSUB DoUSBIn
FOR k = 0 TO 15
WRITE k, USBBuffer[k]
NEXT k
CPS1_CC = USBBuffer[0]
CPS2_CC = USBBuffer[1]
CPS3_CC = USBBuffer[2]
CPS4_CC = USBBuffer[3]
CPS5_CC = USBBuffer[4]
CPS6_CC = USBBuffer[5]
CPENC1_CC = USBBuffer[6]
CPENC2_CC = USBBuffer[7]
CPENC3_CC = USBBuffer[8]
CPENC4_CC = USBBuffer[9]




PAUSE 1000
GOSUB DoUSBOut

PAUSE 1000
UCON.3 = 0

for i = 0 to 20
toggle led1
pause 200
next i
led1 = 0



RETURN
'************************************************* ******************************
'************************************************* *****************************


InitMPC23017:
Pause 100
'=================== PORTA ================================================== ==
i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[IOCONA,IOCONSETA] 'IOCON register setting
i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[IODIRA,$FF] 'PortA inputs
i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[IOLATA,$FF] 'PortA = 0
'i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[IPOLA,0] 'Input polarity 1= opposite 0 = normal
'i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[DEFVALA,0] 'Default value register
i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[GPPUA,$FF] 'pull-ups enabled 1 = enable 0 = disable
'i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[INTCONA,0] 'INTERRUPT-ON-CHANGE CONTROL REGISTER
'i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[GPINTENA,$FF] 'interupt on change 1= enable 0 = disable
'==================== PORTB ================================================== ==
i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[IOCONB,IOCONSETB]
i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[IODIRB,$FF] 'PortB inputs
i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[IOLATB,$FF]
i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[GPPUB,$FF] 'pull-ups enabled 1 = enable 0 = disable
'i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[IPOLB,0]
'i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[DEFVALB,0]
'i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[INTCONB,0]
'i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[GPINTENB,0]
return
ReInitPortA:
i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[IOCONA,IOCONSETA]
i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[IODIRA,$FF]
i2cwrite I2C_Data,I2C_CLK,IO_EXP0WR,[GPPUA,$FF] 'pull-ups enabled

return
'************************************************* *****************************

Scale:
select case sl_ADC[j]
case 126
volout = 0
case 114
volout = 15
case 110, 112
volout = 30
case 104, 106
volout = 45
case 98
volout = 60
case 86
volout = 75
case 62
volout = 90
case 38
volout = 105
case 0
volout = 125
case else

end select


Control = j + Upper + lower + bass ' drawbars are CC 12-20
HSEROUT [channel,control,volout] ' send data out serial port as midi information
sl_old[j] = sl_ADC[j]

return
'************************************************* ******************************
SortArray: 'Soer data small to large
CounterA=0
SortLoop:
If RawData(CounterA+1) < RawData(CounterA) then
RawData(CounterA) = RawData(CounterA) ^ RawData(CounterA+1)
RawData(CounterA+1+0) = RawData(CounterA) ^ RawData(CounterA+1)
RawData(CounterA) = RawData(CounterA) ^ RawData(CounterA+1)
If CounterA > 0 then CounterA=CounterA-2
endif
CounterA=CounterA+1
If CounterA < 15 then goto SortLoop

' Take the middle eight and average
' C1 = (RAWDATA[4] + RAWDATA[5] + RAWDATA[6] + RAWDATA[7] + RAWDATA[8] + RAWDATA[9] + RAWDATA[10] + RAWDATA[11]) / 8
c1 = 0
for i = 6 to 9
c1 = c1 + rawdata[i]
next i
c1 = c1 / 4
Return
'************************************************* *****************************
'
' Main Loop
'
'************************************************* *****************************

MainLoop:

'SLIDERS 1-9
for j = 0 to 8
'Take 16 samoles
for k = 0 to 15
ADCIN j,c0 ' read Volume pot and place value in C0
rawdata[k] = c0
next k
gosub sortarray
sl_ADC[j] = (C1 >>2)*2 ' convert reading to a midi value from 1-127
If sl_ADC[j] <> sl_old[j] Then ' check to see if the value has changed
gosub scale
Endif
next j
' EXPRESSION Pedal
ADCIN 9,exp
exp1 = exp >> 1
if expold <> exp1 then
HSEROUT [177,11,exp1]
expold = exp1
endif
switchbank = PORTD & %11110000
if switchbank <> switchbankold then
if switchbank.7 = 0 then '
if sw1_flag = 0 then
sw1_flag = 1: led1 = 1: exp_cc = 127
elseif sw1_flag = 1 then
sw1_flag = 0: led1 = 0: exp_cc = 0
endif
HSEROUT [177,1,EXP_CC]
endif

'Slider bank selection
if switchbank.4 = 0 then
Upper = 12: lower = 0: bass = 0 'Select upper bank
elseif switchbank.5 = 0 then
Upper = 12: lower = 9: bass = 0 'select lower bank
elseif switchbank.6 = 0 then
Upper = 12: lower = 9: bass = 12 'select bass bank
endif



switchbankold = switchbank
endif
'================ MCP23017 Decoder ============================================
i2cread I2C_Data,I2C_CLK,IO_EXP0rd,gpioa,[IO_data] 'read 23017
if io_data != io_dat_olda then
'-----------------------------------------------------------------------------
if io_data.0 = 0 and io_data.5 = 0 then

gosub program
endif

'-----------------------------------------------------------------------------
if io_data.0 = 0 then
if cps1_flag = 0 then
cps1_flag = 1: CPS1 = 127
elseif cps1_flag = 1 then
cps1_flag = 0: CPS1 = 0
endif
HSEROUT [177,cps1_cc, CPS1] '"SW1"
endif
'-----------------------------------------------------------------------------
if io_data.1 = 0 then
if cps2_flag = 0 then
cps2_flag = 1: CPS2 = 127
elseif cps2_flag = 1 then
cps2_flag = 0: CPS2 = 0
endif

HSEROUT [177,cps2_cc, cps2] '"SW2"
endif
'-----------------------------------------------------------------------------
if io_data.2 = 0 then
if cps3_flag = 0 then
cps3_flag = 1: CPS3 = 127
elseif cps3_flag = 1 then
cps3_flag = 0: CPS3 = 0
endif

HSEROUT [177,cps3_cc, cps3] '"SW3"
endif
'-----------------------------------------------------------------------------
if io_data.3 = 0 then
if cps4_flag = 0 then
cps4_flag = 1: CPS4 = 127
elseif cps4_flag = 1 then
cps4_flag = 0: CPS4 = 0
endif
HSEROUT [177,cps4_cc, cps4] '"SW4"
endif
'-----------------------------------------------------------------------------
if io_data.4 = 0 then
if cps5_flag = 0 then
cps5_flag = 1: CPS5 = 127
elseif cps5_flag = 1 then
cps5_flag = 0: CPS5 = 0
endif


HSEROUT [177,cps5_cc, cps5] ' "SW5"
endif
'-----------------------------------------------------------------------------
if io_data.5 = 0 then
if cps6_flag = 0 then
cps6_flag = 1: CPS6 = 127
elseif cps6_flag = 1 then
cps6_flag = 0: CPS6 = 0
endif
HSEROUT [177,cps6_cc, cps6] ' "SW6"
endif
pause 250
endif

'-----------------------------------------------------------------------------
i2cread I2C_Data,I2C_CLK,IO_EXP0rd,gpiob,[IO_datb] 'read 23017

if io_datb != io_dat_oldb then

enc1 = io_datb & enc1_mask
if enc1_old = enc1 then goto Encoder2
enctemp = enc1.bit1 ^ enc1_old.bit0
if enctemp = 1 then goto Inc1
Enc1_val = Enc1_val - 1
if enc1_val < 1 then enc1_val = 1
HSEROUT [177,cpenc1_cc,enc1_val]
goto Encoder2
Inc1:
Enc1_val = Enc1_val + 1
if enc1_val => 127 then enc1_val = 127
HSEROUT [177,cpenc1_cc,enc1_val]
'---------------------------------------------------------------------------
Encoder2:

enc2 = io_datb & enc2_mask
if enc2_old = enc2 then goto Encoder3
enctemp = enc2.bit3 ^ enc2_old.bit2
if enctemp = 1 then goto Inc2
Enc2_val = Enc2_val - 1
if enc2_val < 1 then enc2_val = 1
HSEROUT [177,cpenc2_cc,enc2_val]
goto encoder3
Inc2:
Enc2_val = Enc2_val + 1
if enc2_val => 127 then enc2_val = 127
HSEROUT [177,cpenc2_cc,enc2_val]

'---------------------------------------------------------------------------
Encoder3:

enc3 = io_datb & enc3_mask
if enc3_old = enc3 then goto Encoder4
enctemp = enc3.bit5 ^ enc3_old.bit4
if enctemp = 1 then goto Inc3
Enc3_val = Enc3_val - 1
if enc3_val < 1 then enc3_val = 1
HSEROUT [177,cpenc3_cc,enc3_val]
goto encoder4
Inc3:
Enc3_val = Enc3_val + 1
if enc3_val => 127 then enc3_val = 127
HSEROUT [177,cpenc3_cc,enc3_val]

'---------------------------------------------------------------------------
Encoder4:

enc4 = io_datb & enc4_mask
if enc4_old = enc4 then goto Encend
enctemp = enc4.bit7 ^ enc4_old.bit6
if enctemp = 1 then goto Inc4
Enc4_val = Enc4_val - 1
if enc4_val < 1 then enc4_val = 1
HSEROUT [177,cpenc4_cc,enc4_val]
goto encend
Inc4:
Enc4_val = Enc4_val + 1
if enc4_val => 127 then enc4_val = 127
HSEROUT [177,cpenc4_cc,enc4_val]
EncEnd:

'-----------------------------------------------------------------------------
enc1_old = enc1
enc2_old = enc2
enc3_old = enc3
enc4_old = enc4

io_dat_olda = io_data
io_dat_oldb = io_datb
endif

'================================================= ==============================


goto MainLoop
end










' USB descriptors for a HID device
'USBMEMORYADDRESS Con $400 ' USB RAM starts here (set in device header file)
USBMEMORYSIZE Con 256 ' USB RAM size in bytes
USBReservedMemory Var Byte[USBMEMORYSIZE] USBMEMORYADDRESS ' Reserve memory used by USB assembler code

goto hid_desc_end ' Skip over all of the USB assembler code
asm

#define USB_EP0_BUFF_SIZE 64 ; 8, 16, 32, or 64
#define USB_MAX_NUM_INT 1 ; For tracking Alternate Setting
#define USB_MAX_EP_NUMBER 1 ; UEP1
#define NUM_CONFIGURATIONS 1
#define NUM_INTERFACES 1

#define UCFG_VAL USB_PULLUP_ENABLE|USB_INTERNAL_TRANSCEIVER|USB_FUL L_SPEED|USB_PING_PONG__NO_PING_PONG
;#define UCFG_VAL USB_PULLUP_ENABLE|USB_INTERNAL_TRANSCEIVER|USB_LOW _SPEED|USB_PING_PONG__NO_PING_PONG

;#define USE_SELF_POWER_SENSE_IO
;#define USE_USB_BUS_SENSE_IO

#define USB_POLLING

; HID
; Endpoints Allocation
#define HID_INTF_ID 0x00
#define HID_EP 1
#define HID_INT_OUT_EP_SIZE 64
#define HID_INT_IN_EP_SIZE 64
#define HID_NUM_OF_DSC 1

include "usb_hid.asm" ; Include rest of USB files, starting with HID class code

; ************************************************** ****************
; This table is polled by the host immediately after USB Reset has been released.
; This table defines the maximum packet size EP0 can take.
; See section 9.6.1 of the Rev 1.0 USB specification.
; These fields are application DEPENDENT. Modify these to meet
; your specifications.
; ************************************************** ****************
DeviceDescriptor
retlw (EndDeviceDescriptor-DeviceDescriptor)/2 ; bLength Length of this descriptor
retlw USB_DESCRIPTOR_DEVICE ; bDescType This is a DEVICE descriptor
retlw 0x10 ; bcdUSBUSB Revision 1.10 (low byte)
retlw 0x01 ; high byte
retlw 0x00 ; bDeviceClass zero means each interface operates independently
retlw 0x00 ; bDeviceSubClass
retlw 0x00 ; bDeviceProtocol
retlw USB_EP0_BUFF_SIZE ; bMaxPacketSize for EP0

; idVendor (low byte, high byte)
retlw 0xA6
retlw 0x01

; idProduct (low byte, high byte)
retlw 0xDB
retlw 0x07

retlw 0x00 ; bcdDevice (low byte)
retlw 0x00 ; (high byte)
retlw 0x01 ; iManufacturer (string index)
retlw 0x02 ; iProduct (string index)

; iSerialNumber (string index)
retlw 0x03
retlw NUM_CONFIGURATIONS ; bNumConfigurations
EndDeviceDescriptor

; ************************************************** ****************
; This table is retrieved by the host after the address has been set.
; This table defines the configurations available for the device.
; See section 9.6.2 of the Rev 1.0 USB specification (page 184).
; These fields are application DEPENDENT.
; Modify these to meet your specifications.
; ************************************************** ****************
; Configuration pointer table
USB_CD_Ptr
Configs
db low Config1, high Config1
db upper Config1, 0

; Configuration Descriptor
Config1
retlw (Interface1-Config1)/2 ; bLength Length of this descriptor
retlw USB_DESCRIPTOR_CONFIGURATION ; bDescType 2=CONFIGURATION
Config1Len
retlw low ((EndConfig1 - Config1)/2) ; Length of this configuration
retlw high ((EndConfig1 - Config1)/2)
retlw 0x01 ; bNumInterfaces Number of interfaces
retlw 0x01 ; bConfigValue Configuration Value
retlw 0x00 ; iConfig (string index)
retlw _DEFAULT|_SELF ; bmAttributes attributes - bus powered

; Max power consumption (2X mA)
retlw 0x32
Interface1
retlw (HIDDescriptor1-Interface1)/2 ; length of descriptor
retlw USB_DESCRIPTOR_INTERFACE
retlw 0x00 ; number of interface, 0 based array
retlw 0x00 ; alternate setting
retlw 0x02 ; number of endpoints used in this interface
retlw 0x03 ; interface class - assigned by the USB
retlw 0x00 ; boot device
retlw 0x00 ; interface protocol
retlw 0x00 ; index to string descriptor that describes this interface
HIDDescriptor1
retlw (Endpoint1In-HIDDescriptor1)/2 ; descriptor size (9 bytes)
retlw DSC_HID ; descriptor type (HID)
retlw 0x11 ; HID class release number (1.11)
retlw 0x01
retlw 0x00 ; Localized country code (none)
retlw 0x01 ; # of HID class descriptor to follow (1)
retlw 0x22 ; Report descriptor type (HID)
ReportDescriptor1Len
retlw low ((EndReportDescriptor1-ReportDescriptor1)/2)
retlw high ((EndReportDescriptor1-ReportDescriptor1)/2)
Endpoint1In
retlw (EndPoint1Out-Endpoint1In)/2 ; length of descriptor
retlw USB_DESCRIPTOR_ENDPOINT
retlw HID_EP|_EP_IN ; EP1, In
retlw _INT ; Interrupt
retlw low (HID_INT_IN_EP_SIZE) ; This should be the size of the endpoint buffer
retlw high (HID_INT_IN_EP_SIZE)
retlw 0x0A ; Polling interval
EndPoint1Out
retlw (EndConfig1-EndPoint1Out)/2 ; Length of this Endpoint Descriptor
retlw USB_DESCRIPTOR_ENDPOINT ; bDescriptorType = 5 for Endpoint Descriptor
retlw HID_EP|_EP_OUT ; Endpoint number & direction
retlw _INT ; Transfer type supported by this Endpoint
retlw low (HID_INT_OUT_EP_SIZE) ; This should be the size of the endpoint buffer
retlw high (HID_INT_OUT_EP_SIZE)
retlw 0x0A ; Polling interval
EndConfig1

ReportDescriptor1
; vendor defined usage page
retlw 0x06
retlw 0x00
retlw 0xFF

; vendor defined usage
retlw 0x09
retlw 0x00

; collection(application)
retlw 0xA1
retlw 0x01

; *** INPUT REPORT ***

; vendor defined usage
retlw 0x09
retlw 0x01

retlw 0x15 ; logical minimum (-128)
retlw 0x80 ;
retlw 0x25 ; logical maximum (127)
retlw 0x7F ;
retlw 0x35 ; Physical Minimum (0)
retlw 0x00 ;
retlw 0x45 ; Physical Maximum (255)
retlw 0xFF ;

; report size in bits
retlw 0x75
retlw 0x08

; report count (number of fields)
retlw 0x95
retlw 0x10

; Input (Data, Variable, Absolute)
retlw 0x81
retlw 0x02

; *** OUTPUT REPORT ***

; vendor defined usage
retlw 0x09 ; usage (Vendor Defined)
retlw 0x02 ;

retlw 0x15 ; logical minimum (-128)
retlw 0x80 ;
retlw 0x25 ; logical maximum (127)
retlw 0x7F ;
retlw 0x35 ; Physical Minimum (0)
retlw 0x00 ;
retlw 0x45 ; Physical Maximum (255)
retlw 0xFF ;

; report size in bits
retlw 0x75
retlw 0x08

; report count (number of fields)
retlw 0x95
retlw 0x10

; Output (Data, Variable, Absolute)
retlw 0x91
retlw 0x02

retlw 0xC0 ; end collection

EndReportDescriptor1

; String pointer table
USB_SD_Ptr
Strings
db low String0, high String0
db upper String0, 0
db low String1, high String1
db upper String1, 0
db low String2, high String2
db upper String2, 0
db low String3, high String3
db upper String3, 0

String0
retlw (String1-String0)/2 ; Length of string
retlw USB_DESCRIPTOR_STRING ; Descriptor type 3
retlw 0x09 ; Language ID (as defined by MS 0x0409)
retlw 0x04

; company name
String1
retlw (String2-String1)/2
retlw USB_DESCRIPTOR_STRING

retlw 'D'
retlw 0x00
retlw 'L'
retlw 0x00
retlw 'C'
retlw 0x00
retlw 'I'
retlw 0x00
retlw 'N'
retlw 0x00
retlw 'C'
retlw 0x00


; product name
String2
retlw (String3-String2)/2
retlw USB_DESCRIPTOR_STRING

retlw 'U'
retlw 0x00
retlw 'S'
retlw 0x00
retlw 'B'
retlw 0x00
retlw '_'
retlw 0x00
retlw 'M'
retlw 0x00
retlw 'I'
retlw 0x00
retlw 'D'
retlw 0x00
retlw 'I'
retlw 0x00


; serial number
String3
retlw (String4-String3)/2
retlw USB_DESCRIPTOR_STRING

retlw '1'
retlw 0x00
retlw '0'
retlw 0x00
retlw '0'
retlw 0x00
retlw '2'
retlw 0x00

String4


endasm
hid_desc_end

RuudNL
- 11th November 2017, 14:10
Thanks!
Yes, that looks like a good starting point!
I will study your example and try to get things working.

RuudNL
- 11th November 2017, 15:17
Which PIC did you use? (I will first try if everything compiles before I modify the file(s) )

RuudNL
- 11th November 2017, 21:47
DaveC3, your code has been a great help so far.
Unfortunately, I didn't manage to get it working.
I suppose there is something wrong with my fuse settings.
Do you mind to give me your config settings?
(I stripped most of your code in the body, but the PIC isn't recognised as a MIDI device.)

DaveC3
- 11th November 2017, 23:33
I think I used a 18F4550 for this project. if you haven't already, I would suggest you first make simple HID project to see if you can get your PC to recognize your device. If you send me your e-mail address I will send you the whole project in a zip file.

Here is the .LST file for the project, you can see the fuse setting I used.



MPASM 5.43 USB_MIDI.ASM 2-3-2012 20:25:46 PAGE 1


LOC OBJECT CODE LINE SOURCE TEXT
VALUE

00001
00002 ; PICBASIC PRO(TM) Compiler 3.0.4.4, (c) 1998, 2011 microEngineering Labs, Inc. All Rights Reserved.
00000001 00003 MPASMWIN_USED EQU 1
00004
00005 #define PBP_PATH C:\PBP3\
00006
00007
00008
00009
00016 LIST
00017 LIST p = 18F4550, r = dec, w = -311, w = -230, f = inhx32
00018 INCLUDE "P18F4550.INC" ; MPASM Header
00001 LIST
00002
00003 ;================================================= =========================
00004 ; MPASM PIC18F4550 processor include
00005 ;
00006 ; (c) Copyright 1999-2011 Microchip Technology, All rights reserved
00007 ;================================================= =========================
00008
01764 LIST
00021 LIST
00F00000 00022 EEPROM_START EQU 0F00000h
00000020 00023 BLOCK_SIZE EQU 32
00024
00025
00026 PBP_HARDWAREDEF macro
00027 endm
00028
00029
00030 __CONFIG _CONFIG1L, _PLLDIV_5_1L & _CPUDIV_OSC1_PLL2_1L & _USBDIV_2_1L
300000 3EE4 00031 __CONFIG _CONFIG1H, _FOSC_HSPLL_HS_1H & _FCMEN_OFF_1H & _IESO_OFF_1H
00032 __CONFIG _CONFIG2L, _PWRT_OFF_2L & _BOR_ON_2L & _BORV_3_2L & _VREGEN_ON_2L
300002 F3FF 00033 __CONFIG _CONFIG2H, _WDT_ON_2H & _WDTPS_512_2H
300004 F9FF 00034 __CONFIG _CONFIG3H, _CCP2MX_ON_3H & _PBADEN_OFF_3H & _LPT1OSC_OFF_3H & _MCLRE_ON_3H
300006 FF9B 00035 __CONFIG _CONFIG4L, _STVREN_ON_4L & _LVP_OFF_4L & _ICPRT_OFF_4L & _XINST_OFF_4L
00036
00037
00038
00039 ; Define statements.
00040 ; C:\PBP3\USB18\USB_MIDI\PICBASICPRO\USB_MIDI.PBP 00007 DEFINE WRITE_INT 1
00041 #define WRITE_INT 1
00042 ; C:\PBP3\USB18\USB_MIDI\PICBASICPRO\USB_MIDI.PBP 00008 Define LOADER_USED 1
00043 #define LOADER_USED 1
00044 ; C:\PBP3\USB18\USB_MIDI\PICBASICPRO\USB_MIDI.PBP 00009 DEFINE RESET_ORG 800h ' For Microchip US
B Bootloader
00045 #define RESET_ORG 800h
00046 ; C:\PBP3\USB18\USB_MIDI\PICBASICPRO\USB_MIDI.PBP 00010 DEFINE INTERRUPT_ORG 808h ' For Microchi
p USB Bootloader
00047 #define INTERRUPT_ORG 808h
00048 ; C:\PBP3\USB18\USB_MIDI\PICBASICPRO\USB_MIDI.PBP 00012 DEFINE OSC 48 ' tell p
rogram we are using a 20mhz oscillator
00049 #define OSC 48
MPASM 5.43 USB_MIDI.ASM 2-3-2012 20:25:46 PAGE 2