aboutsummaryrefslogtreecommitdiff
path: root/tests/stm32/src/bin/usart.rs
blob: ef7efe96aeb9e2cb6a87ca642f364123cbb09da0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#![no_std]
#![no_main]
#[path = "../common.rs"]
mod common;

use common::*;
use defmt::{assert, assert_eq, unreachable};
use embassy_executor::Spawner;
use embassy_stm32::mode::Blocking;
use embassy_stm32::usart::{Config, ConfigError, Error, Uart};
use embassy_time::{Duration, Instant, block_for};

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
    let p = init();
    info!("Hello World!");

    // Arduino pins D0 and D1
    // They're connected together with a 1K resistor.
    let mut usart = peri!(p, UART);
    let mut rx = peri!(p, UART_RX);
    let mut tx = peri!(p, UART_TX);

    {
        let config = Config::default();
        let mut usart = Uart::new_blocking(usart.reborrow(), rx.reborrow(), tx.reborrow(), config).unwrap();

        let test_usart = async |usart: &mut Uart<'_, Blocking>| -> Result<(), Error> {
            // We can't send too many bytes, they have to fit in the FIFO.
            // This is because we aren't sending+receiving at the same time.

            let data = [0xC0, 0xDE];
            usart.blocking_write(&data)?;

            let mut buf = [0; 2];
            usart.blocking_read(&mut buf)?;
            assert_eq!(buf, data);

            // Test flush doesn't hang.
            usart.blocking_write(&data)?;
            usart.blocking_flush()?;

            // Test flush doesn't hang if there's nothing to flush
            usart.blocking_flush()?;

            Ok(())
        };

        let mut is_ok = false;
        for _ in 0..3 {
            match test_usart(&mut usart).await {
                Ok(()) => is_ok = true,
                Err(Error::Noise) => is_ok = false,
                Err(e) => defmt::panic!("{}", e),
            }

            if is_ok {
                break;
            }
        }

        assert!(is_ok);
    }

    // Test error handling with with an overflow error
    {
        let config = Config::default();
        let mut usart = Uart::new_blocking(usart.reborrow(), rx.reborrow(), tx.reborrow(), config).unwrap();

        // Send enough bytes to fill the RX FIFOs off all USART versions.
        let data = [0; 64];
        usart.blocking_write(&data).unwrap();
        usart.blocking_flush().unwrap();

        // USART can still take up to 1 bit time (?) to receive the last byte
        // that we just flushed, so wait a bit.
        // otherwise, we might clear the overrun flag from an *earlier* byte and
        // it gets set again when receiving the last byte is done.
        block_for(Duration::from_millis(1));

        // The error should be reported first.
        let mut buf = [0; 1];
        let err = usart.blocking_read(&mut buf);
        assert_eq!(err, Err(Error::Overrun));

        // At least the first data byte should still be available on all USART versions.
        usart.blocking_read(&mut buf).unwrap();
        assert_eq!(buf[0], data[0]);
    }

    // Test that baudrate divider is calculated correctly.
    // Do it by comparing the time it takes to send a known number of bytes.
    for baudrate in [300, 9600, 115200, 250_000, 337_934, 1_000_000, 2_000_000] {
        info!("testing baudrate {}", baudrate);

        let mut config = Config::default();
        config.baudrate = baudrate;
        let mut usart = match Uart::new_blocking(usart.reborrow(), rx.reborrow(), tx.reborrow(), config) {
            Ok(x) => x,
            Err(ConfigError::BaudrateTooHigh) => {
                info!("baudrate too high");
                assert!(baudrate >= 1_000_000);
                continue;
            }
            Err(ConfigError::BaudrateTooLow) => {
                info!("baudrate too low");
                assert!(baudrate <= 300);
                continue;
            }
            Err(_) => unreachable!(),
        };

        let n = (baudrate as usize / 100).max(64);

        let start = Instant::now();
        for _ in 0..n {
            usart.blocking_write(&[0x00]).unwrap();
        }
        usart.blocking_flush().unwrap();
        let dur = Instant::now() - start;
        let want_dur = Duration::from_micros(n as u64 * 10 * 1_000_000 / (baudrate as u64));
        let fuzz = want_dur / 5;
        if dur < want_dur - fuzz || dur > want_dur + fuzz {
            defmt::panic!(
                "bad duration for baudrate {}: got {:?} want {:?}",
                baudrate,
                dur,
                want_dur
            );
        }
    }

    info!("Test OK");
    cortex_m::asm::bkpt();
}