tttapa / Control-Surface

Arduino library for creating MIDI controllers and other MIDI devices.
GNU General Public License v3.0
1.24k stars 139 forks source link

support for STM32 devices? #230

Open yogiVan opened 4 years ago

yogiVan commented 4 years ago

Lib looks fantastic, would like to see support for stm32, I.E. blue pill or larger devices. TNX

tttapa commented 4 years ago

The Arduino STM32 Core doesn't seem follow the Arduino Core API, and there are some differences regarding the implementation of the pin functions and constants. You should be able to get it to compile using some platform-specific #ifdefs, though. (The ancient compiler it uses could be an issue, although it should be possible, the Due uses the same compiler and is supported, but it took some tweaks to get it to work.)

However, it's not high up on my TODO list, as I don't own any STM32 boards, so I can't test anything, and - most importantly - because I have yet to find a well-supported Arduino-compatible MIDI over USB implementation for STM32.

lmoe commented 4 years ago

So I'm currently at the same stage. I got Control-Surface to compile.

I'm having a BAITE Maple Mini (green)

It does require setting defines (STM32;NUM_DIGITAL_PINS 35;NUM_ANALOG_INPUTS 9;), and you need to remove the INPUT/OUTPUT/INPUT_PULLUP constants. Ive wrapped them around a ifndef STM32.

pinMode calls need to get casted to the correct type as well.

Next to Arduino STM32 Core, there is also the Arduino_STM32 project. It does offer a way to communicate MIDI. Also as a real MIDI USB device.

However, as you've said, the MIDI implementation of the STM32 Lib differs (https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/master/STM32F1/libraries/USBComposite/USBMIDI.cpp). It doesn't have such an easy method like read/write as the abstractions are using in Control-Surface.

One way would be to copy some parts, and write your own MIDI abstraction yourself. The USB Composite is the root of the communication there. This is what the STM32 MIDI implementation is using as well.

Thanks to the great abstraction of this library, it may be possible.

Ill dig a bit into it, but I'm not sure if I want to spend too much time on it right now. I probably will anyway.

tttapa commented 4 years ago

Thanks for that link, didn't know that USBMIDI library existed. To interface that library with Control Surface, it should be enough to implement these three functions: https://github.com/tttapa/Control-Surface/blob/ae7aa01da639b6c7e991a739a6f5751fd91bd1e0/src/MIDI_Interfaces/USBMIDI_Interface.hpp#L66-L71 Looking at the STM32 USBMIDI examples, you'll probably have to override the MIDI_Interface::begin() function as well.

The first two functions map almost directly to USBMIDI::writePacket and USBMIDI::readPacket, but be careful to only call USBMIDI::readPacket if USBMIDI::available returns a non-zero number of available packets, otherwise readPacket will block. If there are no packets available, simply return a packet of all zeros to Control Surface.

USBMIDI::writePacket seems to flush automatically, so you don't have to implement USBMIDI_Interface::flushUSB.

You might be able to use the C API instead of the object-oriented USBMIDI class (I don't think you can have multiple MIDI USB endpoints). See https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/7a7659d1116c11422a3025713cd5c208da991c86/STM32F1/libraries/USBComposite/usb_midi_device.h#L170-L178.

lmoe commented 4 years ago

Thanks for your quick response and your suggestions!

That was kind of the strategic I was going for. I rather try to use the C API, as the C++ one already implements a MIDI functionality (sendNote, etc) besides the protocol. That's what the Control-Surface library is doing already. So using that one appears wrong.

I just need some time to get back into C and the way the library operates. A challenge for the weekend. :)

lmoe commented 4 years ago

@tttapa So this is the current more or less working solution:

https://github.com/lmoe/Control-Surface/commit/59d60ae8ff747069df4bccdd7ec414bf0dcd9480

//---

I've hooked up a potentiometer for testing and I get correct values inside the application. If I turn the potentiometer higher up, it spams out a huge amount of numbers close to the actual value (10 > 11 < 12) in random. The issue however seems to be a user related issue. As analogRead itself gives shaky numbers.

/edit:

So it seems like, changing ADC_RESOLUTION from 10 to 12 does the trick. The issue seemed bigger than it actually was and the hysteresis works flawlessly. No spam anymore. A solid MIDI controller now. :)

//---

It currently only includes the interfacing layer, not the overall changes I had to make in the library to get it to compile. That's very ugly right now.

I'm not really pleased with the current result, as these defines should not be the way to differ as they are doing right now. The Arduino IDE doesn't seem to support preprocessor variables like Visual Studio / vMicro does.

Maybe there is another value I can use, which doesn't need to be defined manually. I'll take a look on that.

I was never really good at C++ and that was 5 years ago. :) Maybe I'll sort it out tomorrow.

tttapa commented 4 years ago

Thanks a lot for sharing! I should have some free time tomorrow to take a deeper look at it.

lmoe commented 4 years ago

You're welcome. :)

Turns out, the ArduinoSTM32 project automatically defines "__STM32F1_\", therefore I have changed everything to that definition. I have also reworked the little port. Less changes were needed now. It should compile now as is.

One bigger issue is the usage of NUM_DIGITAL_PINS and NUM_ANALOG_INPUTS. Those are never defined. I have added them manually. It works for the maple mini, I'm not so sure about other dev boards though.

However, it doesn't require Visual Studio to compile anymore, Arduino IDE is enough now as nothing needs to be defined manually now. A working solution is now pushed.

lmoe commented 4 years ago

So Ive tested the implementation for a few days now and am currently setting up the controller itself with a ST7789v display. This seems to work fine, yay!

I've also tried the SSD1306 one, as examples are already existing. The Arduino_STM32 library ships it's own port of the Adafruit library you are using. It however gets included with a different name: Adafruit_SSD1306_STM32.h instead of Adafruit_SSD1306.h.

I haven't checked if this applies for other libraries, but might be something to consider as it's hardwired inside your DisplayInterfaceSSD1306 interface.

I currently simply use the stock Adafruit ST7789v library and do the updates manually in loop() and that seems to work fine so far. No port of any library was required. Checking for changes will probably be a tedious task though.