I'm trying to implement an UART driver for the msp430fr5969, using rust but I'm struggling to get it to work. To do so, I ported a driver that I wrote in C a long time ago to rust, using the msp430-quickstart project as a template, and a peripheral access crate (PAC) generated with the msp430-svd crate.
The code is the following
let p = msp430fr5969::Peripherals::take().unwrap();
...
disable watchdog and activate gpio (clear locklpm5 bit)
...
setup_uart(); // function described later
// Activate LED
p.PORT_1_2.p1dir.modify(|_, w| w.p1dir0().set_bit());
p.PORT_1_2.p1out.modify(|_, w| w.p1out0().set_bit());
loop {
delay(50_000);
// Say hi via uart
put_char(&p, 'h'); // function described later
put_char(&p, 'i');
put_char(&p, '\n');
// Toggle LED
p.PORT_1_2.p1out.modify(|r, w| w.p1out0().bit(!r.p1out0().bit()));
}
In the current state, the rust program compiles and run on the target without any problem (the leds are blinking). However, it doesn't output anything on my serial console.
The code of put_char
and setup_uart
is available below. Note that register appended with a W (e.g uca0ctlw
) are word-access registers address, and with a number are byte-access registers address (e.g uca0ctl1
is the lower part of uca0ctlw
and uca0ctl0
it's upper part).
The svd generated by msp430-svd crate indicates the correct base address for the USCI_A0 interface.
The rust functions
pub put_char(&p, c: char) {
// Actively wait until UART is not busy (does not block there, as leds
// are blinking
while p.USCI_A0_UART_MODE.uca0statw.read().ucbusy().bit_is_set() {};
// Write the character to the TXbuffer, which is supposed to send
// the character over uart
p.USCI_A0_UART_MODE.uca0txbuf.write(|w| unsafe { w.bits(c as u16) });
}
pub setup_uart(&p) {
// set IO fonction to 10b for P2.0 (Tx) and P2.1 (Rx)
p12.p2sel0.modify(|_,w|w.p2sel0_0().clear_bit().p2sel0_1().clear_bit());
p12.p2sel1.modify(|_,w|w.p2sel1_0().set_bit().p2sel1_1().set_bit());
let uart = p.USCI_A0_UART_MODE;
// Perform software reset
uart.uca0ctl1.modify(|r, w| unsafe { w.bits(r.bits() | 0x1) });
// Select SMCLK as a clock
uart.uca0ctl1.modify(|r, w| unsafe { w.bits(r.bits() | 0x80) });
// Set Baud rate to 9600
uart.uca0br0.write(|w| unsafe { w.bits(110) });
uart.uca0br1.write(|w| unsafe{ w.bits(0)});
// Get out of reset state
uart.uca0ctl1.modify(|r, w| unsafe { w.bits(r.bits() & !0x1) });
}
The original c functions
void setup_uart(void) {
/* set IO: fonction 10 for P2.0 (Tx) and P2.1 (Rx) */
P2SEL0 &= ~0x03;
P2SEL1 |= 0x03;
/* set Software reset (and reinit register) */
UCA0CTLW0 = UCSWRST;
/* default 8N1, lsb first, uart, input clk SMCLK */
UCA0CTLW0 |= UCSSEL__SMCLK;
/* baud rates are pre-calculated for 9600. */
UCA0BRW = 110;
UCA0MCTLW = tpl_mctlwTab[dcoConfig];
/* get out of reset state */
UCA0CTLW0 &= ~UCSWRST;
}
void put_char(char c) {
while (!(UCA0IFG & UCTXIFG));
UCA0TXBUF = c;
}
As It didn't work, I tried using the code available on the msp430-quickstart example folder: hal.rs. It didn't work either.
I'm not sure if I messed up the configuration, even if it looks pretty similar to the C code, or if I missed something about rust embedded systems programming.
If you have any idea of what could I've gone wrong while porting this driver, please let me know !
Thanks in advance,
Hugo
Documentation: