14
14
//! the embedded-hal read and write traits with `u16` as the word type. You can use these
15
15
//! implementations for 9-bit words.
16
16
17
- use core:: fmt;
18
17
use core:: marker:: PhantomData ;
19
- use core:: ops:: Deref ;
20
-
21
- use crate :: rcc;
22
- use nb:: block;
23
18
24
19
mod hal_02;
25
20
mod hal_1;
26
- mod uart_impls;
21
+
22
+ pub ( crate ) mod uart_impls;
23
+ pub use uart_impls:: Instance ;
24
+ use uart_impls:: RegisterBlockImpl ;
27
25
28
26
use crate :: gpio:: { self , PushPull } ;
29
27
@@ -32,8 +30,6 @@ use crate::pac;
32
30
use crate :: gpio:: NoPin ;
33
31
use crate :: rcc:: Clocks ;
34
32
35
- use crate :: dma:: traits:: PeriAddress ;
36
-
37
33
/// Serial error
38
34
pub use embedded_hal_one:: serial:: ErrorKind as Error ;
39
35
@@ -76,6 +72,51 @@ pub trait TxISR {
76
72
fn is_tx_empty ( & self ) -> bool ;
77
73
}
78
74
75
+ /// Trait for listening [`Rx`] interrupt events.
76
+ pub trait RxListen {
77
+ /// Start listening for an rx not empty interrupt event
78
+ ///
79
+ /// Note, you will also have to enable the corresponding interrupt
80
+ /// in the NVIC to start receiving events.
81
+ fn listen ( & mut self ) ;
82
+
83
+ /// Stop listening for the rx not empty interrupt event
84
+ fn unlisten ( & mut self ) ;
85
+
86
+ /// Start listening for a line idle interrupt event
87
+ ///
88
+ /// Note, you will also have to enable the corresponding interrupt
89
+ /// in the NVIC to start receiving events.
90
+ fn listen_idle ( & mut self ) ;
91
+
92
+ /// Stop listening for the line idle interrupt event
93
+ fn unlisten_idle ( & mut self ) ;
94
+ }
95
+
96
+ /// Trait for listening [`Tx`] interrupt event.
97
+ pub trait TxListen {
98
+ /// Start listening for a tx empty interrupt event
99
+ ///
100
+ /// Note, you will also have to enable the corresponding interrupt
101
+ /// in the NVIC to start receiving events.
102
+ fn listen ( & mut self ) ;
103
+
104
+ /// Stop listening for the tx empty interrupt event
105
+ fn unlisten ( & mut self ) ;
106
+ }
107
+
108
+ /// Trait for listening [`Serial`] interrupt events.
109
+ pub trait Listen {
110
+ /// Starts listening for an interrupt event
111
+ ///
112
+ /// Note, you will also have to enable the corresponding interrupt
113
+ /// in the NVIC to start receiving events.
114
+ fn listen ( & mut self , event : Event ) ;
115
+
116
+ /// Stop listening for an interrupt event
117
+ fn unlisten ( & mut self , event : Event ) ;
118
+ }
119
+
79
120
/// Serial abstraction
80
121
pub struct Serial < USART : CommonPins , WORD = u8 > {
81
122
tx : Tx < USART , WORD > ,
@@ -131,139 +172,35 @@ impl<USART: Instance, WORD> Serial<USART, WORD> {
131
172
) ,
132
173
config : impl Into < config:: Config > ,
133
174
clocks : & Clocks ,
134
- ) -> Result < Self , config:: InvalidConfig > {
135
- use self :: config:: * ;
136
-
137
- let config = config. into ( ) ;
138
- unsafe {
139
- // Enable clock.
140
- USART :: enable_unchecked ( ) ;
141
- USART :: reset_unchecked ( ) ;
142
- }
143
-
144
- let pclk_freq = USART :: clock ( clocks) . raw ( ) ;
145
- let baud = config. baudrate . 0 ;
146
-
147
- // The frequency to calculate USARTDIV is this:
148
- //
149
- // (Taken from STM32F411xC/E Reference Manual,
150
- // Section 19.3.4, Equation 1)
151
- //
152
- // 16 bit oversample: OVER8 = 0
153
- // 8 bit oversample: OVER8 = 1
154
- //
155
- // USARTDIV = (pclk)
156
- // ------------------------
157
- // 8 x (2 - OVER8) x (baud)
158
- //
159
- // BUT, the USARTDIV has 4 "fractional" bits, which effectively
160
- // means that we need to "correct" the equation as follows:
161
- //
162
- // USARTDIV = (pclk) * 16
163
- // ------------------------
164
- // 8 x (2 - OVER8) x (baud)
165
- //
166
- // When OVER8 is enabled, we can only use the lowest three
167
- // fractional bits, so we'll need to shift those last four bits
168
- // right one bit
169
-
170
- // Calculate correct baudrate divisor on the fly
171
- let ( over8, div) = if ( pclk_freq / 16 ) >= baud {
172
- // We have the ability to oversample to 16 bits, take
173
- // advantage of it.
174
- //
175
- // We also add `baud / 2` to the `pclk_freq` to ensure
176
- // rounding of values to the closest scale, rather than the
177
- // floored behavior of normal integer division.
178
- let div = ( pclk_freq + ( baud / 2 ) ) / baud;
179
- ( false , div)
180
- } else if ( pclk_freq / 8 ) >= baud {
181
- // We are close enough to pclk where we can only
182
- // oversample 8.
183
- //
184
- // See note above regarding `baud` and rounding.
185
- let div = ( ( pclk_freq * 2 ) + ( baud / 2 ) ) / baud;
186
-
187
- // Ensure the the fractional bits (only 3) are
188
- // right-aligned.
189
- let frac = div & 0xF ;
190
- let div = ( div & !0xF ) | ( frac >> 1 ) ;
191
- ( true , div)
192
- } else {
193
- return Err ( config:: InvalidConfig ) ;
194
- } ;
195
-
196
- usart. brr . write ( |w| unsafe { w. bits ( div) } ) ;
197
-
198
- // Reset other registers to disable advanced USART features
199
- usart. cr2 . reset ( ) ;
200
- usart. cr3 . reset ( ) ;
201
-
202
- // Enable transmission and receiving
203
- // and configure frame
204
-
205
- usart. cr1 . write ( |w| {
206
- w. ue ( ) . set_bit ( ) ;
207
- w. over8 ( ) . bit ( over8) ;
208
- w. te ( ) . set_bit ( ) ;
209
- w. re ( ) . set_bit ( ) ;
210
- w. m ( ) . bit ( config. wordlength == WordLength :: DataBits9 ) ;
211
- w. pce ( ) . bit ( config. parity != Parity :: ParityNone ) ;
212
- w. ps ( ) . bit ( config. parity == Parity :: ParityOdd )
213
- } ) ;
214
-
215
- match config. dma {
216
- DmaConfig :: Tx => usart. cr3 . write ( |w| w. dmat ( ) . enabled ( ) ) ,
217
- DmaConfig :: Rx => usart. cr3 . write ( |w| w. dmar ( ) . enabled ( ) ) ,
218
- DmaConfig :: TxRx => usart. cr3 . write ( |w| w. dmar ( ) . enabled ( ) . dmat ( ) . enabled ( ) ) ,
219
- DmaConfig :: None => { }
220
- }
175
+ ) -> Result < Self , config:: InvalidConfig >
176
+ where
177
+ <USART as Instance >:: RegisterBlock : uart_impls:: RegisterBlockImpl ,
178
+ {
179
+ <USART as Instance >:: RegisterBlock :: new ( usart, pins, config, clocks)
180
+ }
181
+ }
221
182
222
- Ok ( Serial {
223
- tx : Tx :: new ( usart, pins. 0 . into ( ) ) ,
224
- rx : Rx :: new ( pins. 1 . into ( ) ) ,
225
- }
226
- . config_stop ( config) )
183
+ impl < UART : CommonPins , WORD > Serial < UART , WORD > {
184
+ pub fn split ( self ) -> ( Tx < UART , WORD > , Rx < UART , WORD > ) {
185
+ ( self . tx , self . rx )
227
186
}
228
187
229
188
#[ allow( clippy:: type_complexity) ]
230
- pub fn release ( self ) -> ( USART , ( USART :: Tx < PushPull > , USART :: Rx < PushPull > ) ) {
189
+ pub fn release ( self ) -> ( UART , ( UART :: Tx < PushPull > , UART :: Rx < PushPull > ) ) {
231
190
( self . tx . usart , ( self . tx . pin , self . rx . pin ) )
232
191
}
233
192
}
234
193
235
- impl < USART : Instance , WORD > Serial < USART , WORD > {
236
- fn config_stop ( self , config : config:: Config ) -> Self {
237
- self . tx . usart . set_stopbits ( config. stopbits ) ;
238
- self
239
- }
240
- }
241
-
242
- use crate :: pac:: usart1 as uart_base;
243
-
244
- // Implemented by all USART instances
245
- pub trait Instance :
246
- crate :: Sealed
247
- + Deref < Target = uart_base:: RegisterBlock >
248
- + rcc:: Enable
249
- + rcc:: Reset
250
- + rcc:: BusClock
251
- + CommonPins
252
- {
253
- #[ doc( hidden) ]
254
- fn ptr ( ) -> * const uart_base:: RegisterBlock ;
255
- #[ doc( hidden) ]
256
- fn set_stopbits ( & self , bits : config:: StopBits ) ;
257
- }
258
-
259
194
macro_rules! halUsart {
260
- ( $USART: ty, $usart : ident , $ Serial: ident, $Tx: ident, $Rx: ident) => {
195
+ ( $USART: ty, $Serial: ident, $Tx: ident, $Rx: ident) => {
261
196
pub type $Serial<WORD = u8 > = Serial <$USART, WORD >;
262
197
pub type $Tx<WORD = u8 > = Tx <$USART, WORD >;
263
198
pub type $Rx<WORD = u8 > = Rx <$USART, WORD >;
264
199
265
200
impl Instance for $USART {
266
- fn ptr( ) -> * const uart_base:: RegisterBlock {
201
+ type RegisterBlock = crate :: serial:: uart_impls:: RegisterBlockUsart ;
202
+
203
+ fn ptr( ) -> * const crate :: serial:: uart_impls:: RegisterBlockUsart {
267
204
<$USART>:: ptr( ) as * const _
268
205
}
269
206
@@ -285,9 +222,112 @@ macro_rules! halUsart {
285
222
}
286
223
pub ( crate ) use halUsart;
287
224
288
- halUsart ! { pac:: USART1 , usart1 , Serial1 , Rx1 , Tx1 }
289
- halUsart ! { pac:: USART2 , usart2 , Serial2 , Rx2 , Tx2 }
290
- halUsart ! { pac:: USART6 , usart6 , Serial6 , Rx6 , Tx6 }
225
+ halUsart ! { pac:: USART1 , Serial1 , Rx1 , Tx1 }
226
+ halUsart ! { pac:: USART2 , Serial2 , Rx2 , Tx2 }
227
+ halUsart ! { pac:: USART6 , Serial6 , Rx6 , Tx6 }
291
228
292
229
#[ cfg( feature = "usart3" ) ]
293
- halUsart ! { pac:: USART3 , usart3, Serial3 , Rx3 , Tx3 }
230
+ halUsart ! { pac:: USART3 , Serial3 , Rx3 , Tx3 }
231
+
232
+ impl < UART : CommonPins > Rx < UART , u8 > {
233
+ pub ( crate ) fn with_u16_data ( self ) -> Rx < UART , u16 > {
234
+ Rx :: new ( self . pin )
235
+ }
236
+ }
237
+
238
+ impl < UART : CommonPins > Rx < UART , u16 > {
239
+ pub ( crate ) fn with_u8_data ( self ) -> Rx < UART , u8 > {
240
+ Rx :: new ( self . pin )
241
+ }
242
+ }
243
+
244
+ impl < UART : CommonPins > Tx < UART , u8 > {
245
+ pub ( crate ) fn with_u16_data ( self ) -> Tx < UART , u16 > {
246
+ Tx :: new ( self . usart , self . pin )
247
+ }
248
+ }
249
+
250
+ impl < UART : CommonPins > Tx < UART , u16 > {
251
+ pub ( crate ) fn with_u8_data ( self ) -> Tx < UART , u8 > {
252
+ Tx :: new ( self . usart , self . pin )
253
+ }
254
+ }
255
+
256
+ impl < UART : CommonPins , WORD > Rx < UART , WORD > {
257
+ pub ( crate ) fn new ( pin : UART :: Rx < PushPull > ) -> Self {
258
+ Self {
259
+ _word : PhantomData ,
260
+ pin,
261
+ }
262
+ }
263
+
264
+ pub fn join ( self , tx : Tx < UART , WORD > ) -> Serial < UART , WORD > {
265
+ Serial { tx, rx : self }
266
+ }
267
+ }
268
+
269
+ impl < UART : CommonPins , WORD > Tx < UART , WORD > {
270
+ pub ( crate ) fn new ( usart : UART , pin : UART :: Tx < PushPull > ) -> Self {
271
+ Self {
272
+ _word : PhantomData ,
273
+ usart,
274
+ pin,
275
+ }
276
+ }
277
+
278
+ pub fn join ( self , rx : Rx < UART , WORD > ) -> Serial < UART , WORD > {
279
+ Serial { tx : self , rx }
280
+ }
281
+ }
282
+
283
+ impl < UART : Instance , WORD > AsRef < Tx < UART , WORD > > for Serial < UART , WORD > {
284
+ #[ inline( always) ]
285
+ fn as_ref ( & self ) -> & Tx < UART , WORD > {
286
+ & self . tx
287
+ }
288
+ }
289
+
290
+ impl < UART : Instance , WORD > AsRef < Rx < UART , WORD > > for Serial < UART , WORD > {
291
+ #[ inline( always) ]
292
+ fn as_ref ( & self ) -> & Rx < UART , WORD > {
293
+ & self . rx
294
+ }
295
+ }
296
+
297
+ impl < UART : Instance , WORD > AsMut < Tx < UART , WORD > > for Serial < UART , WORD > {
298
+ #[ inline( always) ]
299
+ fn as_mut ( & mut self ) -> & mut Tx < UART , WORD > {
300
+ & mut self . tx
301
+ }
302
+ }
303
+
304
+ impl < UART : Instance , WORD > AsMut < Rx < UART , WORD > > for Serial < UART , WORD > {
305
+ #[ inline( always) ]
306
+ fn as_mut ( & mut self ) -> & mut Rx < UART , WORD > {
307
+ & mut self . rx
308
+ }
309
+ }
310
+
311
+ impl < UART : Instance > Serial < UART , u8 > {
312
+ /// Converts this Serial into a version that can read and write `u16` values instead of `u8`s
313
+ ///
314
+ /// This can be used with a word length of 9 bits.
315
+ pub fn with_u16_data ( self ) -> Serial < UART , u16 > {
316
+ Serial {
317
+ tx : self . tx . with_u16_data ( ) ,
318
+ rx : self . rx . with_u16_data ( ) ,
319
+ }
320
+ }
321
+ }
322
+
323
+ impl < UART : Instance > Serial < UART , u16 > {
324
+ /// Converts this Serial into a version that can read and write `u8` values instead of `u16`s
325
+ ///
326
+ /// This can be used with a word length of 8 bits.
327
+ pub fn with_u8_data ( self ) -> Serial < UART , u8 > {
328
+ Serial {
329
+ tx : self . tx . with_u8_data ( ) ,
330
+ rx : self . rx . with_u8_data ( ) ,
331
+ }
332
+ }
333
+ }
0 commit comments