atmega_hal/
usart.rs

1//! USART
2//!
3//! # Example
4//!
5//! Complete example source code can be found in the repository:
6//! [`atmega2560-usart.rs`](https://github.com/Rahix/avr-hal/blob/main/examples/atmega2560/src/bin/atmega2560-usart.rs)
7//!
8//! *Note: [ufmt](https://crates.io/crates/ufmt/) is used instead of `core::fmt` because
9//! `core::fmt` code quickly grows too large for AVR platforms.*
10//!
11//! ```
12//! let dp = atmega_hal::Peripherals::take().unwrap();
13//! let pins = atmega_hal::pins!(dp);
14//!
15//! let mut serial = Usart::new(
16//!     dp.USART0,
17//!     pins.pe0,
18//!     pins.pe1.into_output(),
19//!     Baudrate::<crate::CoreClock>::new(57600),
20//! );
21//!
22//! ufmt::uwriteln!(&mut serial, "Hello from ATmega!").unwrap();
23//!
24//! loop {
25//!     // Read a byte from the serial connection
26//!     let b = nb::block!(serial.read()).unwrap();
27//!     // Answer
28//!     ufmt::uwriteln!(&mut serial, "Got {}!", b).unwrap();
29//! }
30//! ```
31
32#[allow(unused_imports)]
33use crate::port;
34pub use avr_hal_generic::usart::*;
35
36pub type Usart<USART, RX, TX, CLOCK> =
37    avr_hal_generic::usart::Usart<crate::Atmega, USART, RX, TX, CLOCK>;
38pub type UsartWriter<USART, RX, TX, CLOCK> =
39    avr_hal_generic::usart::UsartWriter<crate::Atmega, USART, RX, TX, CLOCK>;
40pub type UsartReader<USART, RX, TX, CLOCK> =
41    avr_hal_generic::usart::UsartReader<crate::Atmega, USART, RX, TX, CLOCK>;
42
43#[cfg(any(feature = "atmega16"))]
44pub type Usart0<CLOCK> = Usart<
45    crate::pac::USART,
46    port::Pin<port::mode::Input, port::PD0>,
47    port::Pin<port::mode::Output, port::PD1>,
48    CLOCK,
49>;
50#[cfg(any(
51    feature = "atmega88p",
52    feature = "atmega168",
53    feature = "atmega328p",
54    feature = "atmega328pb",
55    feature = "atmega1284p",
56    feature = "atmega164pa"
57))]
58pub type Usart0<CLOCK> = Usart<
59    crate::pac::USART0,
60    port::Pin<port::mode::Input, port::PD0>,
61    port::Pin<port::mode::Output, port::PD1>,
62    CLOCK,
63>;
64#[cfg(any(
65    feature = "atmega88p",
66    feature = "atmega168",
67    feature = "atmega328p",
68    feature = "atmega328pb",
69    feature = "atmega1284p",
70    feature = "atmega164pa"
71))]
72avr_hal_generic::impl_usart_traditional! {
73    hal: crate::Atmega,
74    peripheral: crate::pac::USART0,
75    register_suffix: 0,
76    rx: port::PD0,
77    tx: port::PD1,
78}
79
80#[cfg(feature = "atmega328pb")]
81pub type Usart1<CLOCK> = Usart<
82    crate::pac::USART1,
83    port::Pin<port::mode::Input, port::PB4>,
84    port::Pin<port::mode::Output, port::PB3>,
85    CLOCK,
86>;
87#[cfg(feature = "atmega328pb")]
88avr_hal_generic::impl_usart_traditional! {
89    hal: crate::Atmega,
90    peripheral: crate::pac::USART1,
91    register_suffix: 1,
92    rx: port::PB4,
93    tx: port::PB3,
94}
95
96#[cfg(any(
97    feature = "atmega32u4",
98    feature = "atmega128a",
99    feature = "atmega1280",
100    feature = "atmega2560",
101    feature = "atmega1284p",
102    feature = "atmega164pa"
103))]
104pub type Usart1<CLOCK> = Usart<
105    crate::pac::USART1,
106    port::Pin<port::mode::Input, port::PD2>,
107    port::Pin<port::mode::Output, port::PD3>,
108    CLOCK,
109>;
110#[cfg(any(
111    feature = "atmega32u4",
112    feature = "atmega1280",
113    feature = "atmega2560",
114    feature = "atmega1284p",
115    feature = "atmega164pa"
116))]
117avr_hal_generic::impl_usart_traditional! {
118    hal: crate::Atmega,
119    peripheral: crate::pac::USART1,
120    register_suffix: 1,
121    rx: port::PD2,
122    tx: port::PD3,
123}
124
125#[cfg(any(feature = "atmega128a", feature = "atmega1280", feature = "atmega2560"))]
126pub type Usart0<CLOCK> = Usart<
127    crate::pac::USART0,
128    port::Pin<port::mode::Input, port::PE0>,
129    port::Pin<port::mode::Output, port::PE1>,
130    CLOCK,
131>;
132#[cfg(any(feature = "atmega1280", feature = "atmega2560"))]
133avr_hal_generic::impl_usart_traditional! {
134    hal: crate::Atmega,
135    peripheral: crate::pac::USART0,
136    register_suffix: 0,
137    rx: port::PE0,
138    tx: port::PE1,
139}
140
141#[cfg(any(feature = "atmega1280", feature = "atmega2560"))]
142pub type Usart2<CLOCK> = Usart<
143    crate::pac::USART2,
144    port::Pin<port::mode::Input, port::PH0>,
145    port::Pin<port::mode::Output, port::PH1>,
146    CLOCK,
147>;
148#[cfg(any(feature = "atmega1280", feature = "atmega2560"))]
149avr_hal_generic::impl_usart_traditional! {
150    hal: crate::Atmega,
151    peripheral: crate::pac::USART2,
152    register_suffix: 2,
153    rx: port::PH0,
154    tx: port::PH1,
155}
156
157#[cfg(any(feature = "atmega1280", feature = "atmega2560"))]
158pub type Usart3<CLOCK> = Usart<
159    crate::pac::USART3,
160    port::Pin<port::mode::Input, port::PJ0>,
161    port::Pin<port::mode::Output, port::PJ1>,
162    CLOCK,
163>;
164#[cfg(any(feature = "atmega1280", feature = "atmega2560"))]
165avr_hal_generic::impl_usart_traditional! {
166    hal: crate::Atmega,
167    peripheral: crate::pac::USART3,
168    register_suffix: 3,
169    rx: port::PJ0,
170    tx: port::PJ1,
171}
172
173#[cfg(any(feature = "atmega8", feature = "atmega32a"))]
174pub type Usart0<CLOCK> = Usart<
175    crate::pac::USART,
176    port::Pin<port::mode::Input, port::PD0>,
177    port::Pin<port::mode::Output, port::PD1>,
178    CLOCK,
179>;
180
181// TODO: atmega8 USART is different from other atmegas
182// implemented so far. It uses the same register address
183// for UBRRH and UCSRC, the way to select which register
184// to write to, msb has to be 1 (for UCSRC)
185// or 0 (for UBRRH). Because of the same address,
186// these two are exposed as functions instead of
187// fields.
188#[cfg(any(feature = "atmega8", feature = "atmega32a"))]
189impl
190    crate::usart::UsartOps<
191        crate::Atmega,
192        crate::port::Pin<crate::port::mode::Input, port::PD0>,
193        crate::port::Pin<crate::port::mode::Output, port::PD1>,
194    > for crate::pac::USART
195{
196    fn raw_init<CLOCK>(&mut self, baudrate: crate::usart::Baudrate<CLOCK>) {
197        // msb of ubrrh has to be 0 to set ubrrh register. (see atmega8 datasheet)
198        let ubrrh: u8 = ((baudrate.ubrr >> 8) & 0x0F) as u8;
199        let ubrrl: u8 = (baudrate.ubrr & 0xFF) as u8;
200        self.ubrrh().write(|w| w.bits(ubrrh));
201        self.ubrrl.write(|w| w.bits(ubrrl));
202        self.ucsra.write(|w| w.u2x().bit(baudrate.u2x));
203
204        // Enable receiver and transmitter but leave interrupts disabled.
205        #[rustfmt::skip]
206        self.ucsrb.write(|w| w
207            .txen().set_bit()
208            .rxen().set_bit()
209        );
210
211        // Set frame format to 8n1 for now.  At some point, this should be made
212        // configurable, similar to what is done in other HALs.
213        #[rustfmt::skip]
214        self.ucsrc().write(|w| w
215            .ursel().set_bit() // sets the ucsrc instead of ubrrh (ubrrh and ucsrc share same location on ATmega8, see atmega8 datasheet)
216            .umsel().usart_async()
217            .ucsz().chr8()
218            .usbs().stop1()
219            .upm().disabled()
220        );
221    }
222
223    fn raw_deinit(&mut self) {
224        // Wait for any ongoing transfer to finish.
225        avr_hal_generic::nb::block!(self.raw_flush()).ok();
226        self.ucsrb.reset();
227    }
228
229    fn raw_flush(&mut self) -> avr_hal_generic::nb::Result<(), core::convert::Infallible> {
230        if self.ucsra.read().udre().bit_is_clear() {
231            Err(avr_hal_generic::nb::Error::WouldBlock)
232        } else {
233            Ok(())
234        }
235    }
236
237    fn raw_write(
238        &mut self,
239        byte: u8,
240    ) -> avr_hal_generic::nb::Result<(), core::convert::Infallible> {
241        // Call flush to make sure the data-register is empty
242        self.raw_flush()?;
243
244        self.udr.write(|w| w.bits(byte));
245        Ok(())
246    }
247
248    fn raw_read(&mut self) -> avr_hal_generic::nb::Result<u8, core::convert::Infallible> {
249        if self.ucsra.read().rxc().bit_is_clear() {
250            return Err(avr_hal_generic::nb::Error::WouldBlock);
251        }
252
253        Ok(self.udr.read().bits())
254    }
255
256    fn raw_interrupt(&mut self, event: crate::usart::Event, state: bool) {
257        match event {
258            crate::usart::Event::RxComplete => self.ucsrb.modify(|_, w| w.rxcie().bit(state)),
259            crate::usart::Event::TxComplete => self.ucsrb.modify(|_, w| w.txcie().bit(state)),
260            crate::usart::Event::DataRegisterEmpty => {
261                self.ucsrb.modify(|_, w| w.udrie().bit(state))
262            }
263        }
264    }
265}
266
267// TODO: ATmega128A USART1 is also different from other atmegas
268// Mainly needed because ubrr1 is split in ubrr1h and ubrr1l
269#[cfg(any(feature = "atmega128a"))]
270impl
271    crate::usart::UsartOps<
272        crate::Atmega,
273        crate::port::Pin<crate::port::mode::Input, port::PD2>,
274        crate::port::Pin<crate::port::mode::Output, port::PD3>,
275    > for crate::pac::USART1
276{
277    fn raw_init<CLOCK>(&mut self, baudrate: crate::usart::Baudrate<CLOCK>) {
278        let ubrr1h: u8 = (baudrate.ubrr >> 8) as u8;
279        let ubrr1l: u8 = baudrate.ubrr as u8;
280        self.ubrr1h.write(|w| w.bits(ubrr1h));
281        self.ubrr1l.write(|w| w.bits(ubrr1l));
282        self.ucsr1a.write(|w| w.u2x1().bit(baudrate.u2x));
283
284        // Enable receiver and transmitter but leave interrupts disabled.
285        #[rustfmt::skip]
286        self.ucsr1b.write(|w| w
287            .txen1().set_bit()
288            .rxen1().set_bit()
289        );
290
291        // Set frame format to 8n1 for now.  At some point, this should be made
292        // configurable, similar to what is done in other HALs.
293        #[rustfmt::skip]
294        self.ucsr1c.write(|w| w
295            .umsel1().usart_async()
296            .ucsz1().chr8()
297            .usbs1().stop1()
298            .upm1().disabled()
299        );
300    }
301
302    fn raw_deinit(&mut self) {
303        // Wait for any ongoing transfer to finish.
304        avr_hal_generic::nb::block!(self.raw_flush()).ok();
305        self.ucsr1b.reset();
306    }
307
308    fn raw_flush(&mut self) -> avr_hal_generic::nb::Result<(), core::convert::Infallible> {
309        if self.ucsr1a.read().udre1().bit_is_clear() {
310            Err(avr_hal_generic::nb::Error::WouldBlock)
311        } else {
312            Ok(())
313        }
314    }
315
316    fn raw_write(
317        &mut self,
318        byte: u8,
319    ) -> avr_hal_generic::nb::Result<(), core::convert::Infallible> {
320        // Call flush to make sure the data-register is empty
321        self.raw_flush()?;
322
323        self.udr1.write(|w| w.bits(byte));
324        Ok(())
325    }
326
327    fn raw_read(&mut self) -> avr_hal_generic::nb::Result<u8, core::convert::Infallible> {
328        if self.ucsr1a.read().rxc1().bit_is_clear() {
329            return Err(avr_hal_generic::nb::Error::WouldBlock);
330        }
331
332        Ok(self.udr1.read().bits())
333    }
334
335    fn raw_interrupt(&mut self, event: crate::usart::Event, state: bool) {
336        match event {
337            crate::usart::Event::RxComplete => self.ucsr1b.modify(|_, w| w.rxcie1().bit(state)),
338            crate::usart::Event::TxComplete => self.ucsr1b.modify(|_, w| w.txcie1().bit(state)),
339            crate::usart::Event::DataRegisterEmpty => {
340                self.ucsr1b.modify(|_, w| w.udrie1().bit(state))
341            }
342        }
343    }
344}
345
346// TODO: ATmega128A USART0 is also different from other atmegas
347// Mainly needed because ubrr1 is split in ubrr1h and ubrr1l
348// For USART0 they are not even close to eachother in memory
349#[cfg(any(feature = "atmega128a"))]
350impl
351    crate::usart::UsartOps<
352        crate::Atmega,
353        crate::port::Pin<crate::port::mode::Input, port::PE0>,
354        crate::port::Pin<crate::port::mode::Output, port::PE1>,
355    > for crate::pac::USART0
356{
357    fn raw_init<CLOCK>(&mut self, baudrate: crate::usart::Baudrate<CLOCK>) {
358        let ubrr0h: u8 = (baudrate.ubrr >> 8) as u8;
359        let ubrr0l: u8 = baudrate.ubrr as u8;
360        self.ubrr0h.write(|w| w.bits(ubrr0h));
361        self.ubrr0l.write(|w| w.bits(ubrr0l));
362        self.ucsr0a.write(|w| w.u2x0().bit(baudrate.u2x));
363
364        // Enable receiver and transmitter but leave interrupts disabled.
365        self.ucsr0b.write(|w| w.txen0().set_bit().rxen0().set_bit());
366
367        // Set frame format to 8n1 for now.  At some point, this should be made
368        // configurable, similar to what is done in other HALs.
369        #[rustfmt::skip]
370        self.ucsr0c.write(|w| w
371            .umsel0().usart_async()
372            .ucsz0().chr8()
373            .usbs0().stop1()
374            .upm0().disabled()
375        );
376    }
377
378    fn raw_deinit(&mut self) {
379        // Wait for any ongoing transfer to finish.
380        avr_hal_generic::nb::block!(self.raw_flush()).ok();
381        self.ucsr0b.reset();
382    }
383
384    fn raw_flush(&mut self) -> avr_hal_generic::nb::Result<(), core::convert::Infallible> {
385        if self.ucsr0a.read().udre0().bit_is_clear() {
386            Err(avr_hal_generic::nb::Error::WouldBlock)
387        } else {
388            Ok(())
389        }
390    }
391
392    fn raw_write(
393        &mut self,
394        byte: u8,
395    ) -> avr_hal_generic::nb::Result<(), core::convert::Infallible> {
396        // Call flush to make sure the data-register is empty
397        self.raw_flush()?;
398
399        self.udr0.write(|w| w.bits(byte));
400        Ok(())
401    }
402
403    fn raw_read(&mut self) -> avr_hal_generic::nb::Result<u8, core::convert::Infallible> {
404        if self.ucsr0a.read().rxc0().bit_is_clear() {
405            return Err(avr_hal_generic::nb::Error::WouldBlock);
406        }
407
408        Ok(self.udr0.read().bits())
409    }
410
411    fn raw_interrupt(&mut self, event: crate::usart::Event, state: bool) {
412        match event {
413            crate::usart::Event::RxComplete => self.ucsr0b.modify(|_, w| w.rxcie0().bit(state)),
414            crate::usart::Event::TxComplete => self.ucsr0b.modify(|_, w| w.txcie0().bit(state)),
415            crate::usart::Event::DataRegisterEmpty => {
416                self.ucsr0b.modify(|_, w| w.udrie0().bit(state))
417            }
418        }
419    }
420}