cancel
Showing results for 
Search instead for 
Did you mean: 

HAL version of USB ''Class Compliant'' MIDI, can it be done?

Christopher Pappas
Senior II
Posted on September 02, 2016 at 15:52

Hey all!

I am trying to see if I can eliminate the serial port version of MIDI and switch over to using USB MIDI controllers/keyboards instead.

Searching on this forum (and Google as well), I see many attempts at creating this, mostly poorly documented and or proprietary (i.e. - MIOS), and other open source code that doesn't seem to survive the transition from GCC to KEIL, and the rest of what is available is written for SPL only.

Is there an example of a USB MIDI ''Class-Compliant'' code that can be used on the USB-OTG port of STM32 Nucleo boards?

Can an existing piece of code (like the USB Flash Drive FatFS 3rd-party examples in the v1.4.0 firmware) be modified to connect to USB ''Class-Compliant'' devices such as controllers or keyboards?

Does it seem like a feasible task, or is it just too much work to get this to work on HAL?

Does anybody have suggestions or ideas or comments about this subject?

Thanks!!

Christopher

#usb-midi-class #usb-midi-host-nucleo-144 #class-compliant-hal-midi

Note: this post was migrated and contained many threaded conversations, some content may be missing.
21 REPLIES 21
Posted on February 06, 2017 at 23:13

Whery interesting project,

Christopher! Is it possible to see its demo?

Now I'm coding my hybrid paraphonic synthesizer too. It's close to Korg Mono/Poly in architecture and consist of quad DCOs and dual Polyvosk state variable VCF. And I am looking for how to implement two virtual MIDI ports one for MIDI data from DAW and other for Control Face App.

First, needs to modify the descriptor by adding two additional MIDI Jack for input and output. But what to do next is not clear, because I still can't fully understand exactly how the library works

It's work on my STM32F407 Discovery board. I just modify string

&sharpinclude

'stm32f0xx_hal.h' to 'stm32f4xx_hal.h' where the compiler point.

Then I removed all code not directly related to data exchange.

usbd_midi_if.c

&sharpinclude

'usbd_midi_if.h'

&sharpinclude

'stm32f4xx_hal.h'

static

uint16_t MIDI_DataRx(uint8_t *msg, uint16_t length);

static

uint16_t MIDI_DataTx(uint8_t *msg, uint16_t length);

USBD_MIDI_ItfTypeDef USBD_Interface_fops_FS =

{

 

MIDI_DataRx,

 

MIDI_DataTx

};

static

uint16_t MIDI_DataRx(uint8_t *msg, uint16_t length)

{

  uint8_t chan = msg[

1

] &

0xf

;

 

uint8_t msgtype = msg[

1

] &

0xf0

;

 

uint8_t b1 =

 

msg[

2

];

 

uint8_t b2 =

 

msg[

3

];

 

uint16_t b = ((b2 &

0x7f

) <<

7

) | (b1 &

0x7f

);

 

switch

(msgtype) {

 

case

0x80

:

         

HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_13); //blink LED

         

break

;

 

case

0x90

:

         

HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_13); 

//blink LED

         

break

;

 

case

0xB0

:

         

break

;

 

case

0xC0

:

         

break

;

 

case

0xD0

:

         

break

;

 

case

0xE0

:

         

break

;

 

default

:

         

break

;

 

}

 

return

0

;

}

static

uint16_t MIDI_DataTx(uint8_t *msg, uint16_t length)

{

 

uint32_t i =

0

;

 

while

(i < length) {

   

APP_Rx_Buffer[APP_Rx_ptr_in] = *(msg + i);

   

APP_Rx_ptr_in++;

   

i++;

   

if

(APP_Rx_ptr_in == APP_RX_DATA_SIZE) {

     

APP_Rx_ptr_in =

0

;

   

}

 

}

 

return

USBD_OK;

}

Even when I switched the compiler in C++, I got the following errors:

Error[Pe167]: argument of type 'char const *' is incompatible with parameter of type 'uint8_t *'

Error[Pe167]: argument of type 'void *' is incompatible with parameter of type 'USBD_HandleTypeDef *'

I did an explicit conversion of types where needed, putting (uint8_t*) and (

USBD_HandleTypeDef*).

Posted on February 08, 2017 at 05:12

It's done! I modified the descriptorand now it showsas two separate MIDI ports(cables).

usbd_midi.c

___________________________

***

__ALIGN_BEGIN uint8_t USBD_MIDI_CfgDesc[USB_MIDI_CONFIG_DESC_SIZ] __ALIGN_END =

{

// configuration descriptor

0x09

,

0x02

, DESC_SIZ_LOBYTE, DESC_SIZ_HIBYTE,

0x02

,

0x01

,

0x00

,

0x80

,

0x31

,

//

USB_MIDI_CONFIG_DESC_SIZ = 133,

DESC_SIZ_LOBYTE =133,

DESC_SIZ_HIBYTE = 0

// The Audio Interface Collection

0x09

,

0x04

,

0x00

,

0x00

,

0x00

,

0x01

,

0x01

,

0x00

,

0x02

,

// Standard AC Interface Descriptor

0x09

,

0x24

,

0x01

,

0x00

,

0x01

,

0x09

,

0x00

,

0x01

,

0x01

,

// Class-specific AC Interface Descriptor

0x09

,

0x04

,

0x01

,

0x00

,

0x02

,

0x01

,

0x03

,

0x00

,

0x02

,

// MIDIStreaming Interface Descriptors

0x07

,

0x24

,

0x01

,

0x00

,

0x01

,

0x41

,

0x00

,

// Class-Specific MS Interface Header Descriptor

// MIDI IN JACKS

0x06

,

0x24

,

0x02

,

0x01

,

0x01

,

0x00

,

0x06

,

0x24

,

0x02

,

0x02

,

0x02

,

0x00

,

// MIDI OUT JACKS

0x09

,

0x24

,

0x03

,

0x01

,

0x03

,

0x01

,

0x02

,

0x01

,

0x00

,

0x09

,

0x24

,

0x03

,

0x02

,

0x04

,

0x01

,

0x01

,

0x01

,

0x00

,

// MIDI IN JACKS

0x06

,

0x24

,

0x02

,

0x01

,

0x05

,

0x00

,

0x06

,

0x24

,

0x02

,

0x02

,

0x06

,

0x00

,

// MIDI OUT JACKS

0x09

,

0x24

,

0x03

,

0x01

,

0x07

,

0x01

,

0x06

,

0x01

,

0x00

,

0x09

,

0x24

,

0x03

,

0x02

,

0x08

,

0x01

,

0x05

,

0x01

,

0x00

,

// OUT endpoint descriptor

0x09

,

0x05

, MIDI_OUT_EP,

0x02

,

0x40

,

0x00

,

0x00

,

0x00

,

0x00

,

0x06

,

0x25

,

0x01

,

0x02

,

0x01

,

0x05

,

// IN endpoint descriptor

0x09

,

0x05

, MIDI_IN_EP,

0x02

,

0x40

,

0x00

,

0x00

,

0x00

,

0x00

,

0x06

,

0x25

,

0x01

,

0x02

,

0x03

,

0x07

,

};

***

_________________

usbd_midi_if.c

_________________

***

static

uint16_t MIDI_DataRx(uint8_t *msg, uint16_t length)

{

uint8_t chan = msg[

1

] &

0xf

;

uint8_t msgtype = msg[

1

] &

0xf0

;

uint8_t b1 = msg[

2

];

uint8_t b2 = msg[

3

];

uint16_t b = ((b2 &

0x7f

) <<

7

) | (b1 &

0x7f

);

switch

(msgtype) {

case

0x80

:

if

( (msg[

0

]>>

4

) ==

0

) HAL_GPIO_WritePin(GPIOD,GPIO_PIN_13, GPIO_PIN_RESET);

if

( (msg[

0

]>>

4

) ==

1

) HAL_GPIO_WritePin(GPIOD,GPIO_PIN_15, GPIO_PIN_RESET);

if

(length>

4

) /* if more then two events came at the same time */

{

//

if

( (msg[

4

]>>

4

) ==

0

) HAL_GPIO_WritePin(GPIOD,GPIO_PIN_12, GPIO_PIN_RESET);

if

( (msg[

4

]>>

4

) ==

1

) HAL_GPIO_WritePin(GPIOD,GPIO_PIN_14, GPIO_PIN_RESET);

}

break

;

case

0x90

:

if

( (msg[

0

]>>

4

) ==

0

) HAL_GPIO_WritePin(GPIOD,GPIO_PIN_13, GPIO_PIN_SET);

if

( (msg[

0

]>>

4

) ==

1

) HAL_GPIO_WritePin(GPIOD,GPIO_PIN_15, GPIO_PIN_SET);

if

(length>

4

)

/* if more then two events came at the same time */

{

//

if

( (msg[

4

]>>

4

) ==

0

) HAL_GPIO_WritePin(GPIOD,GPIO_PIN_12, GPIO_PIN_SET);

if

( (msg[

4

]>>

4

) ==

1

) HAL_GPIO_WritePin(GPIOD,GPIO_PIN_14, GPIO_PIN_SET);

}

break

;

***

Posted on February 10, 2017 at 01:00

Hey Chris - over in the other thread

https://community.st.com/0D50X00009XkYz2SAF

Chinzai Tsuneo suggested that the usbh_MIDI implementation from

Dekrispator was flawed with some incorrect assumptions about control flow in the USB Host. He gave a number of suggestions for correcting that and you came back with a short reply that you had it working.

I've tried the same path you took and I'm having the same problem - the device appears to connect but I never get data from it no matter how hard I mash the keys . Do you have any notes on how you got the MIDI host class to work?

Eric

Posted on February 10, 2017 at 01:47

Hey Eric,

I did not have to modify the HAL hcd code at all, but as a result, I had to modify MIDI_Application.h and 

MIDI_Application.c to add another state to the process.

Posted on February 10, 2017 at 07:28

Thanks Chris - makes sense in light of what was discussed in the other thread. I've been able to use this to get my code working.

Something that I noticed - your switch statement in the packet decoder relies on the event0 byte having a low nybble of 0 (ie MIDI channel 0) so it won't catch messages on other channels. My controller is outputting on channel 1 so no data from it was captured. I did a logical AND with 0xF0 in the parameter of the switch statement to make the decoder more promiscuous.

PS - nice to see someone else working on synth stuff. F7 is great for that.

Posted on February 11, 2017 at 03:12

Your welcome, Eric.

Yes, I just default to MIDI channel 0, that's why I didn't mask off the channel bits.

The F7 has a balanced mix of speed and peripherals, and the Nucleo-144 boards (at $23 a piece) are perfectly priced for Flash-It/Snap-It/Embed-It projects. 

Christopher Pappas
Senior II
Posted on September 21, 2017 at 13:43

For those of you who want to experiment with a VA Synthesizer, check out my

https://community.st.com/0D50X00009bMM4jSAG

project. 
Posted on October 16, 2017 at 10:36

Hello, Alexander!

With your and

Pappas.Chris

helpful posts, I have a working MIDI device with my STM32F429 discovery board. My device is receiving incoming MIDI packets from host. Please, describe me, how I should use a

MIDI_DataTx routineto send MIDI packets to host. Thank you in advance.

Posted on October 30, 2017 at 23:54

Hello Alexander,

I'm trying to modify a CDC USB code from cubeMX to transform it to midi device. Then your post look very interesting for me. Then I download mimuz tuch project and copy the two files (c and h) in my project replacing the original ones for CDC.

I get a stm32 virtual com midi device on MIDI OX but i didn't see any data from my nulceo 64 board (l053) .

I suspect the malloc found on usbd_conf.c 'void *USBD_static_malloc(uint32_t size)

{

  static uint32_t mem[(sizeof(USBD_HandleTypeDef)/4)+1];/* On 32-bit boundary */

  return mem;

}'

I try to replace the original value : USBD_CDC_HandleTypeDef by only USBD_HandleTypeDef (and in the mimuz project is set to 512).

Can you give me more details on how you modify your cube mx original CDC project to get working midi device ?

Regards

Posted on December 08, 2017 at 23:12

Sorry it took so long to respond, bro. I have not included a subscription to the topic.

I pulled the whole driver package from HAL in a separate folder, which can be used without CubeMX

Just add all the files from the USB directory and subdirectories to a project and add some lines from the README file in the corresponding files.

If you have any questions, here is my email:

mailto:eternalengineemi@gmail.com

It have some problems in OsX 9 and later, that i haven't fix yet.

________________

Attachments :

STM_32_HAL_USB_MIDI.zip : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006HyGJ&d=%2Fa%2F0X0000000b5B%2F6suQdVjsOjc18HBLImLnJ9Bc.pWiadRKpF9JEpi9vPA&asPdf=false