【发布时间】:2021-10-03 12:39:09
【问题描述】:
我想在 stm32f1 bluepill 板上使用 UART 生成 Midi 时钟信号。信号基本上只需要以 128 Hz 的最大频率向 31250 bps 串行接口发送一个字节 (0xF8)。我使用 STM32f1s 定时器之一创建了一个最小示例。问题是,我的 midi 设备上接收到的信号似乎不是很稳定。它在 319 和 321 bpm 之间跳跃,而对于 128hz 信号,它应该显示 320bpm 的稳定时钟(转换公式:频率 = bpm * 24 / 60)。你知道为什么会有这么多抖动吗?是串行实现导致抖动还是硬件问题?还是 hal 抽象层引入了抖动?
这是我测量的 124hz 时钟信号之间的时间差:
y 轴上是以 u 秒为单位的时间差,x 轴上是读数的数量。 8000 us 应该是信号之间的正确时间间隔。但在固定的时间间隔内,似乎有一个信号发射,时差仅为约 500。是什么原因造成的?也许是计数器溢出?
将预分频器降低到 12mhz 后,我得到了这个模式:
这是生成时钟信号的代码
#![no_std]
#![no_main]
use cortex_m_rt::entry;
use stm32f1xx_hal::{
pac,
pac::{interrupt, Interrupt, TIM4},
prelude::*,
gpio,
afio,
serial::{Serial, Config},
timer::{Event, Timer, CountDownTimer},
};
use core::mem::MaybeUninit;
use stm32f1xx_hal::pac::{USART2};
pub use embedded_hal::digital::v2::{OutputPin, InputPin};
pub type Usart2Serial = Serial<
USART2, (gpio::gpioa::PA2<gpio::Alternate<gpio::PushPull>>,
gpio::gpioa::PA3<gpio::Input<gpio::Floating>>)>;
// When a panic occurs, stop the microcontroller
#[allow(unused_imports)]
use panic_halt;
static mut G_TIM2: MaybeUninit<CountDownTimer<TIM4>> = MaybeUninit::uninit();
static mut G_SERIAL: MaybeUninit<Usart2Serial> = MaybeUninit::uninit();
#[entry]
fn main() -> ! {
let dp = pac::Peripherals::take().unwrap();
let rcc = dp.RCC.constrain();
let mut flash = dp.FLASH.constrain();
let clocks = rcc.cfgr
.use_hse(8.mhz()) // set clock frequency to external 8mhz oscillator
.sysclk(72.mhz()) // set sysclock
.pclk1(36.mhz()) // clock for apb1 prescaler -> TIM1
.pclk2(36.mhz()) // clock for apb2 prescaler -> TIM2,3,4
.adcclk(12.mhz()) // clock for analog digital converters
.freeze(&mut flash.acr);
let mut apb1 = rcc.apb1;
let mut apb2 = rcc.apb2;
let mut gpioa = dp.GPIOA.split(&mut apb2);
let mut afio = dp.AFIO.constrain(&mut apb2);
// init serial
let mut serial = init_usart2(dp.USART2, gpioa.pa2, gpioa.pa3, &mut gpioa.crl, &mut afio, &clocks, &mut apb1);
unsafe { G_SERIAL.write(serial) };
// init timer
let bpm = 320;
let frequency_in_hertz : u32 = (bpm as u32) * 24 / 60;
let mut timer = Timer::tim4(dp.TIM4, &clocks, &mut apb1).start_count_down((frequency_in_hertz).hz());
timer.listen(Event::Update);
// write to global static var
unsafe { G_TIM2.write(timer); }
cortex_m::peripheral::NVIC::unpend(Interrupt::TIM4);
unsafe {
cortex_m::peripheral::NVIC::unmask(Interrupt::TIM4);
}
loop {
// do nothing
}
}
fn init_usart2(
usart2: USART2,
pa2: gpio::gpioa::PA2<gpio::Input<gpio::Floating>>,
pa3: gpio::gpioa::PA3<gpio::Input<gpio::Floating>>,
crl: &mut gpio::gpioa::CRL,
afio: &mut afio::Parts,
clocks: &stm32f1xx_hal::rcc::Clocks,
apb1: &mut stm32f1xx_hal::rcc::APB1
) -> Usart2Serial {
let tx = pa2.into_alternate_push_pull(crl);
let rx = pa3;
return Serial::usart2(
usart2,
(tx, rx),
&mut afio.mapr,
Config::default().baudrate(31250.bps()),
*clocks,
apb1,
);
}
#[interrupt]
fn TIM4() {
let serial = unsafe { &mut *G_SERIAL.as_mut_ptr() };
serial.write(0xF8).ok();
let tim2 = unsafe { &mut *G_TIM2.as_mut_ptr() };
tim2.clear_update_interrupt_flag();
}
【问题讨论】: