Select Git revision
usart_clk.rs
usart_clk.rs 5.89 KiB
//! Test the USART1 instance
//!
//! Connect the TX and RX pins to run this test
//!
//! PA2 (TX), PA3(RX) on the MCU is connected to the pin header CN3
//#![deny(unsafe_code)]
#![deny(warnings)]
#![allow(warnings)]
#![feature(proc_macro)]
#![no_std]
extern crate cortex_m_rtfm as rtfm;
extern crate cortex_m_semihosting as semihosting;
extern crate hal;
#[macro_use]
extern crate nb;
#[macro_use]
extern crate nucleo_64;
extern crate stm32f40x;
use hal::usart::USART;
use nucleo_64::time::Hertz;
use rtfm::app;
use core::ptr;
use nucleo_64::apb1;
const BAUD_RATE: Hertz = Hertz(115_200);
app! {
device: nucleo_64::stm32f40x,
}
use stm32f40x::USART2;
fn serial_init(p: &init::Peripherals) {
// RM0368 6.3.9
// enable clock to GPIOA, USART2
p.RCC.ahb1enr.modify(|_, w| w.gpioaen().enable());
// enable clock to
p.RCC.apb1enr.modify(|_, w| w.usart2en().bit(true));
// RM0368 8.4.1
// set output mode for GPIOA
// PA2 = TX (output mode), PA3 = RX (input mode)
p.GPIOA.moder.modify(|_, w| {
w.moder2()
.variant(stm32f40x::gpioa::moder::MODER15W::ALTERNATEMODE)
.moder3()
.variant(stm32f40x::gpioa::moder::MODER15W::ALTERNATEMODE)
});
// we don't care about the speed register atm
// DM00102166
// AF7, Table 9
// PA2 and PA3 is connected to USART2 TX and RX respectively
p.GPIOA.afrl.modify(|_, w| w.afrl2().af7().afrl3().af7());
// 8N1, stop bit
p.USART2.cr2.write(|w| unsafe { w.stop().bits(0b00) });
// baud rate
// let brr :<U::Ticks>= BAUD_RATE.into();
let brr: apb1::Ticks = BAUD_RATE.invert().into();
let brr = brr.0;
assert!(brr >= 16, "impossible baud rate");
p.USART2.brr.write(|w| unsafe { w.bits(brr) });
// disable hardware flow control
// enable DMA TX and RX transfers
p.USART2.cr3.write(|w| {
w.rtse() /* Ready To Send disable */
.clear_bit()
.ctse() /* Clear To Send disable */
.clear_bit()
.dmat() /* Enable DMA Transmit */
.set_bit()
.dmar() /* Enable DMA Receive */
.set_bit()
});
// enable TX, RX; disable parity checking
p.USART2.cr1.write(|w| {
w.ue() /* Usart Enable */
.set_bit()
.re() /* Receiver Enable */
.set_bit()
.te() /* Transmitter Enable */
.set_bit()
.m() /* Word Length, 8 */
.clear_bit()
.pce() /* Parity Control Enable */
.clear_bit()
.rxneie() /* Reception Interrupt Enable */
.clear_bit()
});
}
fn clk_init(p: &init::Peripherals) {
// setting up the flash memory latency
// RM0368 8.4.1 (register), 3.4 Table 6
// we assume 3.3 volt operation, thus 2 cycles for 84mHz
// apb1 will be at 42 MHz
p.FLASH.acr.modify(|_, w| unsafe { w.latency().bits(2) });
println!("Flash latency! {:x}", p.FLASH.acr.read().latency().bits());
p.RCC
.cfgr
.modify(|_, w| w.sw0().clear_bit().sw1().clear_bit()); //Switch to HSI
p.RCC.cfgr.modify(|_, w| unsafe { w.ppre1().bits(4) }); //Configure apb1 prescaler = 2,
p.RCC.apb1enr.modify(|_, w| w.pwren().set_bit());
p.RCC.cr.write(|w| w.pllon().clear_bit());
//Enable PLL
// PP PLLN PLLM
// 0b0000 0000 0000 00 01 0 101010000 010000
// RM0368 6.3.2
// PP 01
p.RCC
.pllcfgr
.write(|w| unsafe { w.bits(0b00000000000000010101010000010000) }); //Configure PLL
p.RCC.cr.modify(|_, w| w.pllon().set_bit()); //Enable PLL
while p.RCC.cr.read().pllrdy().bit_is_clear() {}
p.RCC
.cfgr
.modify(|_, w| w.sw0().clear_bit().sw1().set_bit()); //Switch to PLL
// System configuration controller clock enable
p.RCC.apb2enr.modify(|_, w| w.syscfgen().set_bit());
p.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); //Enable GPIOA clock
p.RCC.ahb1enr.modify(|_, w| w.gpioben().set_bit()); //Enable GPIOB clock
}
#[inline(never)]
fn init(p: init::Peripherals) {
println!("Init!");
// clk_init(&p);
serial_init(&p);
//USART::initialize(p.GPIOA, p.RCC, p.USART2);
USART::send(p.USART2, "\n\n\nUSART \n\r");
loop {
let b = block!(read(p.USART2)).unwrap();
write(p.USART2, b).unwrap();
}
}
// Specialized `Result` type
pub type Result<T> = ::core::result::Result<T, nb::Error<Error>>;
/// An error
#[derive(Debug)]
pub enum Error {
/// De-synchronization, excessive noise or a break character detected
Framing,
/// Noise detected in the received frame
Noise,
/// RX buffer overrun
Overrun,
#[doc(hidden)] _Extensible,
}
fn write(usart2: &USART2, byte: u8) -> Result<()> {
let sr = usart2.sr.read();
if sr.ore().bit_is_set() {
Err(nb::Error::Other(Error::Overrun))
} else if sr.nf().bit_is_set() {
Err(nb::Error::Other(Error::Noise))
} else if sr.fe().bit_is_set() {
Err(nb::Error::Other(Error::Framing))
} else if sr.txe().bit_is_set() {
// NOTE(write_volatile) see NOTE in the `read` method
unsafe { ptr::write_volatile(&usart2.dr as *const _ as *mut u8, byte) }
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
fn read(usart2: &USART2) -> Result<u8> {
let sr = usart2.sr.read();
if sr.ore().bit_is_set() {
Err(nb::Error::Other(Error::Overrun))
} else if sr.nf().bit_is_set() {
Err(nb::Error::Other(Error::Noise))
} else if sr.fe().bit_is_set() {
Err(nb::Error::Other(Error::Framing))
} else if sr.rxne().bit_is_set() {
// NOTE(read_volatile) the register is 9 bits big but we'll only
// work with the first 8 bits
Ok(unsafe {
ptr::read_volatile(&usart2.dr as *const _ as *const u8)
})
} else {
Err(nb::Error::WouldBlock)
}
}
fn idle() -> ! {
// Will never be hit, as
rtfm::bkpt();
// Sleep
loop {
rtfm::wfi();
}
}