esp32/
uart.rs

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

//! UART driver.

use core::cell::Cell;
use kernel::ErrorCode;

use kernel::hil;
use kernel::utilities::cells::OptionalCell;
use kernel::utilities::cells::TakeCell;
use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
use kernel::utilities::registers::{register_bitfields, register_structs, ReadWrite};
use kernel::utilities::StaticRef;

pub const UART0_BASE: StaticRef<UartRegisters> =
    unsafe { StaticRef::new(0x6000_0000 as *const UartRegisters) };

register_structs! {
    pub UartRegisters {
        (0x000 => fifo: ReadWrite<u32, FIFO::Register>),
        (0x004 => int_raw: ReadWrite<u32, INT::Register>),
        (0x008 => int_st: ReadWrite<u32, INT::Register>),
        (0x00C => int_ena: ReadWrite<u32, INT::Register>),
        (0x010 => int_clr: ReadWrite<u32, INT::Register>),
        (0x014 => clkdiv: ReadWrite<u32, CLKDIV::Register>),
        (0x018 => autobaud: ReadWrite<u32, AUTOBAUD::Register>),
        (0x01C => status: ReadWrite<u32, STATUS::Register>),
        (0x020 => conf0: ReadWrite<u32, CONF0::Register>),
        (0x024 => conf1: ReadWrite<u32, CONF1::Register>),
        (0x028 => lowpulse: ReadWrite<u32, LOWPULSE::Register>),
        (0x02C => highpulse: ReadWrite<u32, HIGHPULSE::Register>),
        (0x030 => rxd_cnt: ReadWrite<u32, RXD_CNT::Register>),
        (0x034 => flow_config: ReadWrite<u32, FLOW_CONFIG::Register>),
        (0x038 => sleep_conf: ReadWrite<u32, SLEEP_CONF::Register>),
        (0x03C => swfc_conf: ReadWrite<u32, SWFC_CONF::Register>),
        (0x040 => idle_conf: ReadWrite<u32, IDLE_CONF::Register>),
        (0x044 => rs485_conf: ReadWrite<u32, RS485_CONF::Register>),
        (0x048 => at_cmd_precnt: ReadWrite<u32, AT_CMD_PRECNT::Register>),
        (0x04C => at_cmd_postcnt: ReadWrite<u32, AT_CMD_POSTCNT::Register>),
        (0x050 => at_cmd_gaptout: ReadWrite<u32, AT_CMD_GAPTOUT::Register>),
        (0x054 => at_cmd_char: ReadWrite<u32, AT_CMD_CHAR::Register>),
        (0x058 => mem_conf: ReadWrite<u32, MEM_CONF::Register>),
        (0x05C => _reserved0),
        (0x064 => mem_cnt_status: ReadWrite<u32, MEM_CNT_STATUS::Register>),
        (0x068 => pospulse: ReadWrite<u32, POSPULSE::Register>),
        (0x06C => negpulse: ReadWrite<u32, NEGPULSE::Register>),
        (0x070 => @END),
    }
}

register_bitfields![u32,
    FIFO [
        RXFIFO_RD_BYTE OFFSET(0) NUMBITS(8) [],
    ],
    INT [
        RXFIFO_FULL_INT OFFSET(0) NUMBITS(1) [],
        TXFIFO_EMPTY_INT OFFSET(1) NUMBITS(1) [],
        PARITY_ERR_INT OFFSET(2) NUMBITS(1) [],
        FRM_ERR_INT OFFSET(3) NUMBITS(1) [],
        RXFIFO_OVF_INT OFFSET(4) NUMBITS(1) [],
        DSR_CHG_INT OFFSET(5) NUMBITS(1) [],
        CTS_CHG_INT OFFSET(6) NUMBITS(1) [],
        BRK_DET_INT OFFSET(7) NUMBITS(1) [],
        RXFIFO_TOUT_INT OFFSET(8) NUMBITS(1) [],
        SW_XON_INT OFFSET(9) NUMBITS(1) [],
        SW_XOFF_INT OFFSET(10) NUMBITS(1) [],
        GLITCH_DET_INT OFFSET(11) NUMBITS(1) [],
        TX_BRK_DONE_INT OFFSET(12) NUMBITS(1) [],
        TX_BRK_IDLE_DONE_INT OFFSET(13) NUMBITS(1) [],
        TX_DONE_INT OFFSET(14) NUMBITS(1) [],
        RS485_PARITY_ERR_INT OFFSET(15) NUMBITS(1) [],
        RS485_FRM_ERR_INT OFFSET(16) NUMBITS(1) [],
        RS485_CLASH_INT OFFSET(17) NUMBITS(1) [],
        AT_CMD_CHAR_DET_INT OFFSET(18) NUMBITS(1) [],
    ],
    CLKDIV [
        CLKDIV OFFSET(0) NUMBITS(20) [],
        CLKDIV_FRAG OFFSET(20) NUMBITS(4) [],
    ],
    AUTOBAUD [
        AUTOBAUD_EN OFFSET(0) NUMBITS(1) [],
        GLITCH_FILT OFFSET(8) NUMBITS(8) [],
    ],
    STATUS [
        RXFIFO_CNT OFFSET(0) NUMBITS(8) [],
        ST_URX_OUT OFFSET(8) NUMBITS(4) [],
        DSRN OFFSET(13) NUMBITS(1) [],
        CTSN OFFSET(14) NUMBITS(1) [],
        RXD OFFSET(15) NUMBITS(1) [],
        TXFIFO_CNT OFFSET(16) NUMBITS(8) [],
        ST_UTX_OUT OFFSET(24) NUMBITS(4) [],
        DTRN OFFSET(29) NUMBITS(1) [],
        RTSN OFFSET(30) NUMBITS(1) [],
        TXD OFFSET(31) NUMBITS(1) [],
    ],
    CONF0 [
        PARITY OFFSET(0) NUMBITS(1) [],
        PARITY_EN OFFSET(1) NUMBITS(1) [],
        BIT_NUM OFFSET(2) NUMBITS(2) [],
        STOP_BIT_NUM OFFSET(4) NUMBITS(2) [],
        SW_RTS OFFSET(6) NUMBITS(1) [],
        SW_DTR OFFSET(7) NUMBITS(1) [],
        TXD_BRK OFFSET(8) NUMBITS(1) [],
        IRDA_DPLX OFFSET(9) NUMBITS(1) [],
        IRDA_TX_EN OFFSET(10) NUMBITS(1) [],
        IRDA_WCTL OFFSET(11) NUMBITS(1) [],
        IRDA_TX_INV OFFSET(12) NUMBITS(1) [],
        IRDA_RX_INV OFFSET(13) NUMBITS(1) [],
        LOOPBACK OFFSET(14) NUMBITS(1) [],
        TX_FLOW_EN OFFSET(15) NUMBITS(1) [],
        IRDA_EN OFFSET(16) NUMBITS(1) [],
        RXFIFO_RST OFFSET(17) NUMBITS(1) [],
        TXFIFO_RST OFFSET(18) NUMBITS(1) [],
        RXD_INV OFFSET(19) NUMBITS(1) [],
        CTS_INV OFFSET(20) NUMBITS(1) [],
        DSR_INV OFFSET(21) NUMBITS(1) [],
        TXD_INV OFFSET(22) NUMBITS(1) [],
        RTS_INV OFFSET(23) NUMBITS(1) [],
        DTR_INV OFFSET(24) NUMBITS(1) [],
        TICK_REF_ALWAYS_ON OFFSET(27) NUMBITS(1) [],
    ],
    CONF1 [
        RXFIFO_FULL_THRHD OFFSET(0) NUMBITS(7) [],
        TXFIFO_EMPTY_THRHD OFFSET(8) NUMBITS(6) [],
        RX_FLOW_THRHD OFFSET(16) NUMBITS(6) [],
        RX_FLOW_EN OFFSET(23) NUMBITS(1) [],
        RX_TOUT_THRHD OFFSET(24) NUMBITS(7) [],
        RX_TOUT_EN OFFSET(31) NUMBITS(1) [],
    ],
    LOWPULSE [
        LOWPULSE_MIN_CNT OFFSET(0) NUMBITS(20) [],
    ],
    HIGHPULSE [
        HIGHPULSE_MIN_CNT OFFSET(0) NUMBITS(20) []
    ],
    RXD_CNT [
        RXD_EDGE_CNT OFFSET(0) NUMBITS(10) [],
    ],
    FLOW_CONFIG [
        SW_FLOW_CON_EN OFFSET(0) NUMBITS(1) [],
        XONOFF_DEL OFFSET(1) NUMBITS(1) [],
        FORCE_XON OFFSET(2) NUMBITS(1) [],
        FORCE_XOFF OFFSET(3) NUMBITS(1) [],
        SEND_XON OFFSET(4) NUMBITS(1) [],
        SEND_XOFF OFFSET(5) NUMBITS(1) [],
    ],
    SLEEP_CONF [
        ACTIVE_THRESHOLD OFFSET(0) NUMBITS(10) [],
    ],
    SWFC_CONF [
        XON_THRESHOLD OFFSET(0) NUMBITS(8) [],
        XOFF_THRESHOLD OFFSET(8) NUMBITS(8) [],
        XON_CHAR OFFSET(16) NUMBITS(8) [],
        XOFF_CHAR OFFSET(24) NUMBITS(8) [],
    ],
    IDLE_CONF [
        RX_IDLE_THRHD OFFSET(0) NUMBITS(10) [],
        TX_IDLE_NUM OFFSET(10) NUMBITS(10) [],
        TX_BRK_NUM OFFSET(20) NUMBITS(8) [],
    ],
    RS485_CONF [
        RS485_EN OFFSET(0) NUMBITS(1) [],
        DL0_EN OFFSET(1) NUMBITS(1) [],
        DL1_EN OFFSET(2) NUMBITS(1) [],
        RS485TX_RX_EN OFFSET(3) NUMBITS(1) [],
        RS485RXBY_TX_EN OFFSET(4) NUMBITS(1) [],
        RS485_RX_DLY_NUM OFFSET(5) NUMBITS(1) [],
        RS485_TX_DLY_NUM OFFSET(6) NUMBITS(4) [],
    ],
    AT_CMD_PRECNT [
        PRE_IDLE_NUM OFFSET(0) NUMBITS(24) [],
    ],
    AT_CMD_POSTCNT [
        POST_IDLE_NUM OFFSET(0) NUMBITS(24) [],
    ],
    AT_CMD_GAPTOUT [
        RX_GAP_TOUT OFFSET(0) NUMBITS(24) [],
    ],
    AT_CMD_CHAR [
        AT_CMD_CHAR_REG OFFSET(0) NUMBITS(8) [],
        CHAR_NUM OFFSET(8) NUMBITS(8) [],
    ],
    MEM_CONF [
        MEM_PD OFFSET(0) NUMBITS(1) [],
        RX_SIZE OFFSET(3) NUMBITS(4) [],
        TX_SIZE OFFSET(7) NUMBITS(4) [],
        RX_FLOW_THRHD_H3 OFFSET(15) NUMBITS(3) [],
        RX_TOUT_THRHD_H3 OFFSET(18) NUMBITS(3) [],
        XON_THRESHOLD_H2 OFFSET(21) NUMBITS(2) [],
        XOFF_THRESHOLD_H2 OFFSET(23) NUMBITS(2) [],
        RX_MEM_FULL_THRHD OFFSET(25) NUMBITS(3) [],
        TX_MEM_EMPTY_THRHD OFFSET(28) NUMBITS(3) [],
    ],
    MEM_CNT_STATUS [
        RX_MEM_CNT OFFSET(0) NUMBITS(3) [],
        TX_MEM_CNT OFFSET(3) NUMBITS(3) [],
    ],
    POSPULSE [
        POSEDGE_MIN_CNT OFFSET(0) NUMBITS(20) [],
    ],
    NEGPULSE [
        NEGEDGE_MIN_CNT OFFSET(0) NUMBITS(20) [],
    ],
];

pub struct Uart<'a> {
    registers: StaticRef<UartRegisters>,
    tx_client: OptionalCell<&'a dyn hil::uart::TransmitClient>,
    rx_client: OptionalCell<&'a dyn hil::uart::ReceiveClient>,

    tx_buffer: TakeCell<'static, [u8]>,
    tx_len: Cell<usize>,
    tx_index: Cell<usize>,

    rx_buffer: TakeCell<'static, [u8]>,
    rx_index: Cell<usize>,
    rx_len: Cell<usize>,
}

#[derive(Copy, Clone)]
pub struct UartParams {
    pub baud_rate: u32,
}

impl<'a> Uart<'a> {
    pub fn new(base: StaticRef<UartRegisters>) -> Uart<'a> {
        Uart {
            registers: base,
            tx_client: OptionalCell::empty(),
            rx_client: OptionalCell::empty(),
            tx_buffer: TakeCell::empty(),
            tx_len: Cell::new(0),
            tx_index: Cell::new(0),
            rx_buffer: TakeCell::empty(),
            rx_index: Cell::new(0),
            rx_len: Cell::new(0),
        }
    }

    fn enable_tx_interrupt(&self) {
        let regs = self.registers;

        regs.int_ena.modify(
            INT::TXFIFO_EMPTY_INT::SET
                + INT::TX_BRK_DONE_INT::SET
                + INT::TX_BRK_IDLE_DONE_INT::SET
                + INT::TX_DONE_INT::SET,
        );
    }

    pub fn clear_tx_interrupt(&self) {
        let regs = self.registers;

        regs.int_clr.modify(
            INT::TXFIFO_EMPTY_INT::SET
                + INT::TX_BRK_DONE_INT::SET
                + INT::TX_BRK_IDLE_DONE_INT::SET
                + INT::TX_DONE_INT::SET,
        );
    }

    pub fn disable_tx_interrupt(&self) {
        let regs = self.registers;
        regs.int_ena.modify(
            INT::TXFIFO_EMPTY_INT::CLEAR
                + INT::TX_BRK_DONE_INT::CLEAR
                + INT::TX_BRK_IDLE_DONE_INT::CLEAR
                + INT::TX_DONE_INT::CLEAR,
        );
    }

    fn enable_rx_interrupt(&self) {
        let regs = self.registers;

        regs.int_ena.modify(
            INT::RXFIFO_FULL_INT::SET + INT::RXFIFO_OVF_INT::SET + INT::RXFIFO_TOUT_INT::SET,
        );
    }

    pub fn clear_rx_interrupt(&self) {
        let regs = self.registers;

        regs.int_clr.modify(
            INT::RXFIFO_FULL_INT::SET + INT::RXFIFO_OVF_INT::SET + INT::RXFIFO_TOUT_INT::SET,
        );
    }

    pub fn disable_rx_interrupt(&self) {
        let regs = self.registers;
        regs.int_ena.modify(
            INT::RXFIFO_FULL_INT::CLEAR + INT::RXFIFO_OVF_INT::CLEAR + INT::RXFIFO_TOUT_INT::CLEAR,
        );
    }

    fn tx_progress(&self) {
        let regs = self.registers;
        let idx = self.tx_index.get();
        let len = self.tx_len.get();

        if idx < len {
            // Read from the transmit buffer and send bytes to the UART hardware
            // until either the buffer is empty or the UART hardware is full.
            self.tx_buffer.map(|tx_buf| {
                let tx_len = len - idx;

                for i in 0..tx_len {
                    if regs.status.read(STATUS::TXFIFO_CNT) >= 127 {
                        break;
                    }
                    let tx_idx = idx + i;
                    regs.fifo
                        .write(FIFO::RXFIFO_RD_BYTE.val(tx_buf[tx_idx] as u32));
                    self.tx_index.set(tx_idx + 1)
                }
            });
        }
    }

    fn rx_progress(&self) {
        let regs = self.registers;
        let idx = self.rx_index.get();
        let len = self.rx_len.get();

        if idx < len {
            // Read from the UART hardware and write them to the receive buffer
            // until either the buffer is full or the UART hardware is empty.
            self.rx_buffer.map(|rx_buf| {
                let rx_len = len - idx;

                for i in 0..rx_len {
                    if regs.status.read(STATUS::RXFIFO_CNT) == 0 {
                        break;
                    }
                    let rx_idx = idx + i;
                    rx_buf[rx_idx] = regs.fifo.read(FIFO::RXFIFO_RD_BYTE) as u8;
                    self.rx_index.set(rx_idx + 1)
                }
            });
        }
    }

    pub fn handle_interrupt(&self) {
        let regs = self.registers;
        let intrs = regs.int_st.extract();

        if intrs.is_set(INT::TXFIFO_EMPTY_INT) {
            self.clear_tx_interrupt();
            if self.tx_index.get() == self.tx_len.get() {
                self.disable_tx_interrupt();
                // We sent everything to the UART hardware, now from an
                // interrupt callback we can issue the callback.
                self.tx_client.map(|client| {
                    self.tx_buffer.take().map(|tx_buf| {
                        client.transmitted_buffer(tx_buf, self.tx_len.get(), Ok(()));
                    });
                });
            } else {
                // We have more to transmit, so continue in tx_progress().
                self.tx_progress();
            }
        }

        if intrs.is_set(INT::RXFIFO_FULL_INT) || intrs.is_set(INT::RXFIFO_TOUT_INT) {
            self.clear_rx_interrupt();
            if self.rx_index.get() == self.rx_len.get() {
                self.disable_rx_interrupt();
                // We received everything from the UART hardware, now from an
                // interrupt callback we can issue the callback.
                self.rx_client.map(|client| {
                    self.rx_buffer.take().map(|rx_buf| {
                        client.received_buffer(
                            rx_buf,
                            self.rx_len.get(),
                            Ok(()),
                            hil::uart::Error::None,
                        );
                    });
                });
            } else {
                // We have more to receive, so continue in rx_progress().
                self.rx_progress();
            }
        }
    }

    pub fn transmit_sync(&self, bytes: &[u8]) {
        let regs = self.registers;
        for b in bytes.iter() {
            while regs.status.read(STATUS::TXFIFO_CNT) > 8 {}
            regs.fifo.write(FIFO::RXFIFO_RD_BYTE.val(*b as u32));
        }
    }
}

impl hil::uart::Configure for Uart<'_> {
    fn configure(&self, _params: hil::uart::Parameters) -> Result<(), ErrorCode> {
        // Disable all interrupts for now
        self.disable_rx_interrupt();
        self.disable_tx_interrupt();

        Ok(())
    }
}

impl<'a> hil::uart::Transmit<'a> for Uart<'a> {
    fn set_transmit_client(&self, client: &'a dyn hil::uart::TransmitClient) {
        self.tx_client.set(client);
    }

    fn transmit_buffer(
        &self,
        tx_data: &'static mut [u8],
        tx_len: usize,
    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
        if tx_len == 0 || tx_len > tx_data.len() {
            Err((ErrorCode::SIZE, tx_data))
        } else if self.tx_buffer.is_some() {
            Err((ErrorCode::BUSY, tx_data))
        } else {
            // Save the buffer so we can keep sending it.
            self.tx_buffer.replace(tx_data);
            self.tx_len.set(tx_len);
            self.tx_index.set(0);

            self.enable_tx_interrupt();

            self.tx_progress();
            Ok(())
        }
    }

    fn transmit_word(&self, _word: u32) -> Result<(), ErrorCode> {
        Err(ErrorCode::FAIL)
    }

    fn transmit_abort(&self) -> Result<(), ErrorCode> {
        Err(ErrorCode::FAIL)
    }
}

/* UART receive is not implemented yet, mostly due to a lack of tests available */
impl<'a> hil::uart::Receive<'a> for Uart<'a> {
    fn set_receive_client(&self, client: &'a dyn hil::uart::ReceiveClient) {
        self.rx_client.set(client);
    }

    fn receive_buffer(
        &self,
        rx_buffer: &'static mut [u8],
        rx_len: usize,
    ) -> Result<(), (ErrorCode, &'static mut [u8])> {
        if rx_len == 0 || rx_len > rx_buffer.len() {
            return Err((ErrorCode::SIZE, rx_buffer));
        }

        self.rx_buffer.replace(rx_buffer);
        self.rx_index.set(0);
        self.rx_len.set(rx_len);

        self.enable_rx_interrupt();

        self.rx_progress();

        Ok(())
    }

    fn receive_word(&self) -> Result<(), ErrorCode> {
        Err(ErrorCode::FAIL)
    }

    fn receive_abort(&self) -> Result<(), ErrorCode> {
        Err(ErrorCode::FAIL)
    }
}