rust-embedded-community / usbd-midi

MIT License
46 stars 19 forks source link

Example of usage with STM32 #19

Open snorkman88 opened 6 days ago

snorkman88 commented 6 days ago

Describe the solution you'd like A clear and concise description of what you want to happen.

I am in the process of building my own control surface and would like to use this crate an an STM32F4 Blackpill. Do you have an example that I can use as a starting point?

sourcebox commented 4 days ago

Which HAL are you using for the STM32F4?

snorkman88 commented 2 days ago

Hi there, I am using v1.0.0 for all my projects.

sourcebox commented 2 days ago

I think you mean the embedded-hal crate, but that's not what I was asking. There are several options for HAL implementations targeting an STM32F4 like:

Each of these HALs have their own way to setup things and also contain example code how to use USB in general. The first two options can be used with this crate, embassy however has it's own implementation of a MIDI device class.

snorkman88 commented 2 days ago

Oh my bad, sorry!. I am using stm32f4xx-hal.

sourcebox commented 2 days ago

Here's some code based on the README using a modification of the serial example.

You have to activate the features stm32f411, otg-fs and usb_fs for the stm32f4xx-hal crate, of course and also adapt the clock configuration.

//! USB MIDI example using polling in a busy loop.
//! Target board: any STM32F4 with a OTG FS peripheral and a 25MHz HSE crystal
#![no_std]
#![no_main]

use panic_halt as _;

use cortex_m_rt::entry;
use stm32f4xx_hal::otg_fs::{UsbBus, USB};
use stm32f4xx_hal::{pac, prelude::*};
use usb_device::prelude::*;
use usbd_midi::{
    data::{
        midi::{channel::Channel, message::Message, notes::Note},
        usb_midi::midi_packet_reader::MidiPacketBufferReader,
    },
    midi_device::MidiClass,
};

static mut EP_MEMORY: [u32; 1024] = [0; 1024];

#[entry]
fn main() -> ! {
    let dp = pac::Peripherals::take().unwrap();

    let rcc = dp.RCC.constrain();

    let clocks = rcc
        .cfgr
        .use_hse(25.MHz())
        .sysclk(48.MHz())
        .require_pll48clk()
        .freeze();

    let gpioa = dp.GPIOA.split();

    let usb = USB::new(
        (dp.OTG_FS_GLOBAL, dp.OTG_FS_DEVICE, dp.OTG_FS_PWRCLK),
        (gpioa.pa11, gpioa.pa12),
        &clocks,
    );

    let usb_bus = UsbBus::new(usb, unsafe { &mut EP_MEMORY });

    // Create a MIDI class with 1 input and 1 output jack.
    let mut midi = MidiClass::new(&usb_bus, 1, 1).unwrap();

    let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x5e4))
        .device_class(0)
        .device_sub_class(0)
        .strings(&[StringDescriptors::default()
            .manufacturer("Fake Company")
            .product("Product")
            .serial_number("TEST")])
        .unwrap()
        .build();

    loop {
        if !usb_dev.poll(&mut [&mut midi]) {
            continue;
        }

        let mut buffer = [0; 64];

        if let Ok(size) = midi.read(&mut buffer) {
            let buffer_reader = MidiPacketBufferReader::new(&buffer, size);
            for packet in buffer_reader.into_iter() {
                if let Ok(packet) = packet {
                    match packet.message {
                        Message::NoteOn(Channel::Channel1, Note::C2, ..) => {
                            // Do something.
                        }
                        Message::NoteOff(Channel::Channel1, Note::C2, ..) => {
                            // Do something.
                        }
                        _ => {}
                    }
                }
            }
        }
    }
}
snorkman88 commented 2 days ago

@sourcebox Thanks a lot!!!