-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Example of usage with STM32 #19
Comments
Which HAL are you using for the STM32F4? |
Hi there, I am using v1.0.0 for all my projects. |
I think you mean the 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. |
Oh my bad, sorry!. |
Here's some code based on the README using a modification of the serial example. You have to activate the features //! 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.
}
_ => {}
}
}
}
}
}
} |
@sourcebox Thanks a lot!!! |
@sourcebox I have tried this code with a minor change to punt DP and DM pins into altenate mode (AF10). The code looks like this: // Configure the button pin as input and obtain handle
// On the Blackpill STM32F411CEU6 there is a button connected to pin PA0
// 6) Promote the GPIOA PAC struct
let gpioa: gpio::gpioa::Parts = dp.GPIOA.split();
// Configure USB pins to be of type alternate function 10 (AF10)
let usb_dm: gpio::Pin<'A', 11, gpio::Alternate<10>> = gpioa.pa11.into_alternate();
let usb_dp: gpio::Pin<'A', 12, gpio::Alternate<10>> = gpioa.pa12.into_alternate();
// 7) Configure USB peripheral
let usb = USB::new(
(dp.OTG_FS_GLOBAL, dp.OTG_FS_DEVICE, dp.OTG_FS_PWRCLK),
(usb_dm, usb_dp),
&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();
defmt::info!("Before entering loop");
loop {
if !usb_dev.poll(&mut [&mut midi]) {
continue;
}
defmt::info!("Left USB Poll");
let mut buffer = [0; 64];
let payload = UsbMidiEventPacket::from_midi(
CableNumber::Cable0,
Message::NoteOn(
Channel::Channel1, // Channel
Note::C3, // Note
U7::from(Note::try_from(127 as u8).unwrap()), // Velocity
),
);
let result = midi.send_message(payload);
delay.delay_ms(1000_u32);
} this code compiles fine but it hangs when |
Unfortunately, I don't have the appropriate hardware to run this. Did you activate the |
I have just re-tried enabling |
If the code stalls inside Some suggestions:
Overall, this is the kind of issue that has to be checked on the target hardware with a JTAG debug probe connected. Using that, you can single step the code up to the point where it hangs or crashes. |
Thanks again for the suggestions, I will keep you posted if I make it work. |
I have jsut tested and I can confirm this works. |
Ok, good to know. But the serial device has a much simpler descriptor, so it's not sure whether |
There was some issue with STM32F4 devices mentioned on the tracker a while ago, but this can be unrelated: |
That can be caused by enabling the pullup on the USB D+ line. The host then tries to access the port, but if the clocks aren't 100% correct, then there's no reply. |
Oh I see so if I am understanding correctly, despite DP being configured in alternate mode, there is the need for it to be pulled up? |
I have added a 1.5k pull-up but no change. I am a bit confused, do not understand how is one example working and the other one requires a pull up? |
The pullup is always required, but some STM32 series have it internally, so it just needs to be enabled by the HAL. Others (like the F3 series) need an external pullup. Not sure what's on your board already, but if one example works, then the pullup is working. |
What you also can do: remove just the MIDI class part and check if the device then enumerates. If not, there's some deeper problem like the USB clock not running at exactly 48MHz. |
So just to make sure it is not OS related, I plugged it on a Raspberry Pi 5 running Raspbian and I see
I am testing that in a min. |
If I remove the MIDI class,
right? |
Yes. |
But it's possible that you need to call the |
Same, no changes.
|
That does not seem to be possible since |
That indicates a more fundamental problem in the hardware setup or the clocks. |
Maybe another thing to check would the MCO output...sadly I do not have an oscilloscope. |
Hi @sourcebox, I wanted to say the code you provided in #19 (comment) works fine. The device is listed correctly in Raspbian. Since I am trying to make this work using RTIC, I suppose the issue is related to something else. |
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?
The text was updated successfully, but these errors were encountered: