aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreZio Pan <[email protected]>2024-03-16 21:20:17 +0800
committereZio Pan <[email protected]>2024-03-23 09:15:25 +0800
commitc9f759bb21782eb0487c96a59500310d1283694c (patch)
treeb292c0c1931c0d32064cd203dd657651c6d00de5
parent5d12f594303bdb76bf2356d9fc0661826e2e658e (diff)
stm32 CORDIC: ZeroOverhead for q1.31 and q1.15
-rw-r--r--embassy-stm32/src/cordic/enums.rs13
-rw-r--r--embassy-stm32/src/cordic/mod.rs440
-rw-r--r--embassy-stm32/src/cordic/utils.rs4
3 files changed, 264 insertions, 193 deletions
diff --git a/embassy-stm32/src/cordic/enums.rs b/embassy-stm32/src/cordic/enums.rs
index 3e1c47f7f..37c73f549 100644
--- a/embassy-stm32/src/cordic/enums.rs
+++ b/embassy-stm32/src/cordic/enums.rs
@@ -68,16 +68,3 @@ pub enum Width {
68 Bits32, 68 Bits32,
69 Bits16, 69 Bits16,
70} 70}
71
72/// Cordic driver running mode
73#[derive(Clone, Copy)]
74pub enum Mode {
75 /// After caculation start, a read to RDATA register will block AHB until the caculation finished
76 ZeroOverhead,
77
78 /// Use CORDIC interrupt to trigger a read result value
79 Interrupt,
80
81 /// Use DMA to write/read value
82 Dma,
83}
diff --git a/embassy-stm32/src/cordic/mod.rs b/embassy-stm32/src/cordic/mod.rs
index 997ace113..61277d7e1 100644
--- a/embassy-stm32/src/cordic/mod.rs
+++ b/embassy-stm32/src/cordic/mod.rs
@@ -1,8 +1,9 @@
1//! CORDIC co-processor 1//! CORDIC co-processor
2 2
3use crate::peripherals;
4use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 3use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
5 4
5use crate::peripherals;
6
6mod enums; 7mod enums;
7pub use enums::*; 8pub use enums::*;
8 9
@@ -10,10 +11,6 @@ pub mod utils;
10 11
11pub(crate) mod sealed; 12pub(crate) mod sealed;
12 13
13// length of pre-allocated [u32] memory for CORDIC input,
14// length should be multiple of 2
15const INPUT_BUF_LEN: usize = 8;
16
17/// Low-level CORDIC access. 14/// Low-level CORDIC access.
18#[cfg(feature = "unstable-pac")] 15#[cfg(feature = "unstable-pac")]
19pub mod low_level { 16pub mod low_level {
@@ -31,30 +28,16 @@ pub trait Instance: sealed::Instance + Peripheral<P = Self> + crate::rcc::RccPer
31 28
32/// CORDIC configuration 29/// CORDIC configuration
33pub struct Config { 30pub struct Config {
34 mode: Mode,
35 function: Function, 31 function: Function,
36 precision: Precision, 32 precision: Precision,
37 scale: Scale, 33 scale: Scale,
38 first_result: bool, 34 first_result: bool,
39} 35}
40 36
41// CORDIC running state
42struct State {
43 input_buf: [u32; INPUT_BUF_LEN],
44 buf_index: usize,
45}
46
47impl Config { 37impl Config {
48 /// Create a config for Cordic driver 38 /// Create a config for Cordic driver
49 pub fn new( 39 pub fn new(function: Function, precision: Option<Precision>, scale: Option<Scale>, first_result: bool) -> Self {
50 mode: Mode,
51 function: Function,
52 precision: Option<Precision>,
53 scale: Option<Scale>,
54 first_result: bool,
55 ) -> Self {
56 Self { 40 Self {
57 mode,
58 function, 41 function,
59 precision: precision.unwrap_or_default(), 42 precision: precision.unwrap_or_default(),
60 scale: scale.unwrap_or_default(), 43 scale: scale.unwrap_or_default(),
@@ -133,22 +116,123 @@ impl<'d, T: Instance> Cordic<'d, T> {
133 } else { 116 } else {
134 self.peri.set_result_count(Count::Two) 117 self.peri.set_result_count(Count::Two)
135 } 118 }
119 }
120
121 fn blocking_read_f32(&mut self) -> (f32, Option<f32>) {
122 let reg_value = self.peri.read_result();
123
124 let res1 = utils::q1_15_to_f32((reg_value & ((1u32 << 16) - 1)) as u16);
125
126 // We don't care about whether the function return 1 or 2 results,
127 // the only thing matter is whether user want 1 or 2 results.
128 let res2 = if !self.config.first_result {
129 Some(utils::q1_15_to_f32((reg_value >> 16) as u16))
130 } else {
131 None
132 };
133
134 (res1, res2)
135 }
136}
137
138impl<'d, T: Instance> Drop for Cordic<'d, T> {
139 fn drop(&mut self) {
140 T::disable();
141 }
142}
143
144// q1.31 related
145impl<'d, T: Instance> Cordic<'d, T> {
146 /// Run a CORDIC calculation
147 pub fn blocking_calc_32bit(&mut self, arg1s: &[f64], arg2s: Option<&[f64]>, output: &mut [f64]) -> usize {
148 if arg1s.is_empty() {
149 return 0;
150 }
151
152 assert!(
153 match self.config.first_result {
154 true => output.len() >= arg1s.len(),
155 false => output.len() >= 2 * arg1s.len(),
156 },
157 "Output buf length is not long enough"
158 );
159
160 self.check_input_f64(arg1s, arg2s);
161
162 self.peri.disable_irq();
163 self.peri.disable_write_dma();
164 self.peri.disable_read_dma();
165
166 self.peri.set_result_count(if self.config.first_result {
167 Count::One
168 } else {
169 Count::Two
170 });
171
172 self.peri.set_data_width(Width::Bits32, Width::Bits32);
173
174 let mut output_count = 0;
175
176 let mut consumed_input_len = 0;
177
178 // put double input into cordic
179 if arg2s.is_some() && !arg2s.expect("It's infailable").is_empty() {
180 let arg2s = arg2s.expect("It's infailable");
136 181
137 match self.config.mode { 182 self.peri.set_argument_count(Count::Two);
138 Mode::ZeroOverhead => (), 183
139 Mode::Interrupt => { 184 // Skip 1st value from arg1s, this value will be manually "preload" to cordic, to make use of cordic preload function.
140 self.peri.enable_irq(); 185 // And we preserve last value from arg2s, since it need to manually write to cordic, and read the result out.
186 let double_input = arg1s.iter().skip(1).zip(&arg2s[..arg2s.len() - 1]);
187 // Since we preload 1st value from arg1s, the consumed input length is double_input length + 1.
188 consumed_input_len = double_input.len() + 1;
189
190 // preload first value from arg1 to cordic
191 self.blocking_write_f64(arg1s[0]);
192
193 for (&arg1, &arg2) in double_input {
194 // Since we manually preload a value before,
195 // we will write arg2 (from the actual last pair) first, (at this moment, cordic start to calculating,)
196 // and write arg1 (from the actual next pair), then read the result, to "keep preloading"
197
198 self.blocking_write_f64(arg2);
199 self.blocking_write_f64(arg1);
200 self.blocking_read_f64_to_buf(output, &mut output_count);
141 } 201 }
142 Mode::Dma => { 202
143 self.peri.enable_write_dma(); 203 // write last input value from arg2s, then read out the result
144 self.peri.enable_read_dma(); 204 self.blocking_write_f64(arg2s[arg2s.len() - 1]);
205 self.blocking_read_f64_to_buf(output, &mut output_count);
206 }
207
208 // put single input into cordic
209 let input_left = &arg1s[consumed_input_len..];
210
211 if !input_left.is_empty() {
212 self.peri.set_argument_count(Count::One);
213
214 // "preload" value to cordic (at this moment, cordic start to calculating)
215 self.blocking_write_f64(input_left[0]);
216
217 for &arg in input_left.iter().skip(1) {
218 // this line write arg for next round caculation to cordic,
219 // and read result from last round
220 self.blocking_write_f64(arg);
221 self.blocking_read_f64_to_buf(output, &mut output_count);
145 } 222 }
223
224 // read the last output
225 self.blocking_read_f64_to_buf(output, &mut output_count);
146 } 226 }
227
228 output_count
147 } 229 }
148 230
149 fn blocking_read_f64(&mut self) -> (f64, Option<f64>) { 231 fn blocking_read_f64(&mut self) -> (f64, Option<f64>) {
150 let res1 = utils::q1_31_to_f64(self.peri.read_result()); 232 let res1 = utils::q1_31_to_f64(self.peri.read_result());
151 233
234 // We don't care about whether the function return 1 or 2 results,
235 // the only thing matter is whether user want 1 or 2 results.
152 let res2 = if !self.config.first_result { 236 let res2 = if !self.config.first_result {
153 Some(utils::q1_31_to_f64(self.peri.read_result())) 237 Some(utils::q1_31_to_f64(self.peri.read_result()))
154 } else { 238 } else {
@@ -174,16 +258,14 @@ impl<'d, T: Instance> Cordic<'d, T> {
174 } 258 }
175} 259}
176 260
177impl<'d, T: Instance> Drop for Cordic<'d, T> { 261// q1.15 related
178 fn drop(&mut self) {
179 T::disable();
180 }
181}
182
183// q1.31 related
184impl<'d, T: Instance> Cordic<'d, T> { 262impl<'d, T: Instance> Cordic<'d, T> {
185 /// Run a CORDIC calculation 263 /// Run a CORDIC calculation
186 pub fn calc_32bit(&mut self, arg1s: &[f64], arg2s: Option<&[f64]>, output: &mut [f64]) -> usize { 264 pub fn blocking_calc_16bit(&mut self, arg1s: &[f32], arg2s: Option<&[f32]>, output: &mut [f32]) -> usize {
265 if arg1s.is_empty() {
266 return 0;
267 }
268
187 assert!( 269 assert!(
188 match self.config.first_result { 270 match self.config.first_result {
189 true => output.len() >= arg1s.len(), 271 true => output.len() >= arg1s.len(),
@@ -192,180 +274,182 @@ impl<'d, T: Instance> Cordic<'d, T> {
192 "Output buf length is not long enough" 274 "Output buf length is not long enough"
193 ); 275 );
194 276
195 self.check_input_f64(arg1s, arg2s); 277 self.check_input_f32(arg1s, arg2s);
196
197 self.peri.set_result_count(if self.config.first_result {
198 Count::One
199 } else {
200 Count::Two
201 });
202
203 self.peri.set_data_width(Width::Bits32, Width::Bits32);
204 278
205 let mut output_count = 0; 279 self.peri.disable_irq();
280 self.peri.disable_write_dma();
281 self.peri.disable_read_dma();
206 282
207 let mut consumed_input_len = 0; 283 // In q1.15 mode, 1 write/read to access 2 arguments/results
284 self.peri.set_argument_count(Count::One);
285 self.peri.set_result_count(Count::One);
208 286
209 match self.config.mode { 287 self.peri.set_data_width(Width::Bits16, Width::Bits16);
210 Mode::ZeroOverhead => {
211 // put double input into cordic
212 if arg2s.is_some() && !arg2s.unwrap().is_empty() {
213 let arg2s = arg2s.unwrap();
214 288
215 self.peri.set_argument_count(Count::Two); 289 let mut output_count = 0;
216 290
217 // Skip 1st value from arg1s, this value will be manually "preload" to cordic, to make use of cordic preload function. 291 // In q1.15 mode, we always fill 1 pair of 16bit value into WDATA register.
218 // And we preserve last value from arg2s, since it need to manually write to cordic, and read the result out. 292 // If arg2s is None or empty array, we assume arg2 value always 1.0 (as reset value for ARG2).
219 let double_input = arg1s.iter().skip(1).zip(&arg2s[..arg2s.len() - 1]); 293 // If arg2s has some value, and but not as long as arg1s,
220 // Since we preload 1st value from arg1s, the consumed input length is double_input length + 1. 294 // we fill the reset of arg2 values with last value from arg2s (as q1.31 version does)
221 consumed_input_len = double_input.len() + 1;
222 295
223 // preload first value from arg1 to cordic 296 let arg2_default_value = match arg2s {
224 self.blocking_write_f64(arg1s[0]); 297 Some(arg2s) if !arg2s.is_empty() => arg2s[arg2s.len() - 1],
298 _ => 1.0,
299 };
225 300
226 for (&arg1, &arg2) in double_input { 301 let mut args = arg1s.iter().zip(
227 // Since we manually preload a value before, 302 arg2s
228 // we will write arg2 (from the actual last pair) first, (at this moment, cordic start to calculating,) 303 .unwrap_or(&[])
229 // and write arg1 (from the actual next pair), then read the result, to "keep preloading" 304 .iter()
305 .chain(core::iter::repeat(&arg2_default_value)),
306 );
230 307
231 self.blocking_write_f64(arg2); 308 let (&arg1, &arg2) = args
232 self.blocking_write_f64(arg1); 309 .next()
233 self.blocking_read_f64_to_buf(output, &mut output_count); 310 .expect("This should be infallible, since arg1s is not empty");
234 }
235 311
236 // write last input value from arg2s, then read out the result 312 // preloading 1 pair of arguments
237 self.blocking_write_f64(arg2s[arg2s.len() - 1]); 313 self.blocking_write_f32(arg1, arg2);
238 self.blocking_read_f64_to_buf(output, &mut output_count);
239 }
240 314
241 // put single input into cordic 315 for (&arg1, &arg2) in args {
242 let input_left = &arg1s[consumed_input_len..]; 316 self.blocking_write_f32(arg1, arg2);
317 self.blocking_read_f32_to_buf(output, &mut output_count);
318 }
243 319
244 if !input_left.is_empty() { 320 // read last pair of value from cordic
245 self.peri.set_argument_count(Count::One); 321 self.blocking_read_f32_to_buf(output, &mut output_count);
246 322
247 // "preload" value to cordic (at this moment, cordic start to calculating) 323 output_count
248 self.blocking_write_f64(input_left[0]); 324 }
249 325
250 for &arg in input_left.iter().skip(1) { 326 fn blocking_write_f32(&mut self, arg1: f32, arg2: f32) {
251 // this line write arg for next round caculation to cordic, 327 let reg_value: u32 = utils::f32_to_q1_15(arg1) as u32 + ((utils::f32_to_q1_15(arg2) as u32) << 16);
252 // and read result from last round 328 self.peri.write_argument(reg_value);
253 self.blocking_write_f64(arg); 329 }
254 self.blocking_read_f64_to_buf(output, &mut output_count);
255 }
256 330
257 // read the last output 331 fn blocking_read_f32_to_buf(&mut self, result_buf: &mut [f32], result_index: &mut usize) {
258 self.blocking_read_f64_to_buf(output, &mut output_count); 332 let (res1, res2) = self.blocking_read_f32();
259 } 333 result_buf[*result_index] = res1;
334 *result_index += 1;
260 335
261 output_count 336 if let Some(res2) = res2 {
262 } 337 result_buf[*result_index] = res2;
263 Mode::Interrupt => todo!(), 338 *result_index += 1;
264 Mode::Dma => todo!(),
265 } 339 }
266 } 340 }
341}
267 342
268 fn check_input_f64(&self, arg1s: &[f64], arg2s: Option<&[f64]>) { 343// check input value ARG1, ARG2, SCALE and FUNCTION are compatible with each other
269 let config = &self.config; 344macro_rules! check_input_value {
270 345 ($func_name:ident, $float_type:ty) => {
271 use Function::*; 346 impl<'d, T: Instance> Cordic<'d, T> {
272 347 fn $func_name(&self, arg1s: &[$float_type], arg2s: Option<&[$float_type]>) {
273 // check SCALE value 348 let config = &self.config;
274 match config.function { 349
275 Cos | Sin | Phase | Modulus => assert!(Scale::A1_R1 == config.scale, "SCALE should be 0"), 350 use Function::*;
276 Arctan => assert!( 351
277 (0..=7).contains(&(config.scale as u8)), 352 // check SCALE value
278 "SCALE should be: 0 <= SCALE <= 7" 353 match config.function {
279 ), 354 Cos | Sin | Phase | Modulus => assert!(Scale::A1_R1 == config.scale, "SCALE should be 0"),
280 Cosh | Sinh | Arctanh => assert!(Scale::A1o2_R2 == config.scale, "SCALE should be 1"), 355 Arctan => assert!(
281 356 (0..=7).contains(&(config.scale as u8)),
282 Ln => assert!( 357 "SCALE should be: 0 <= SCALE <= 7"
283 (1..=4).contains(&(config.scale as u8)), 358 ),
284 "SCALE should be: 1 <= SCALE <= 4" 359 Cosh | Sinh | Arctanh => assert!(Scale::A1o2_R2 == config.scale, "SCALE should be 1"),
285 ),
286 Sqrt => assert!(
287 (0..=2).contains(&(config.scale as u8)),
288 "SCALE should be: 0 <= SCALE <= 2"
289 ),
290 }
291
292 // check ARG1 value
293 match config.function {
294 Cos | Sin | Phase | Modulus | Arctan => {
295 assert!(
296 arg1s.iter().all(|v| (-1.0..=1.0).contains(v)),
297 "ARG1 should be: -1 <= ARG1 <= 1"
298 );
299 }
300 360
301 Cosh | Sinh => assert!( 361 Ln => assert!(
302 arg1s.iter().all(|v| (-0.559..=0.559).contains(v)), 362 (1..=4).contains(&(config.scale as u8)),
303 "ARG1 should be: -0.559 <= ARG1 <= 0.559" 363 "SCALE should be: 1 <= SCALE <= 4"
304 ),
305
306 Arctanh => assert!(
307 arg1s.iter().all(|v| (-0.403..=0.403).contains(v)),
308 "ARG1 should be: -0.403 <= ARG1 <= 0.403"
309 ),
310
311 Ln => {
312 match config.scale {
313 Scale::A1o2_R2 => assert!(
314 arg1s.iter().all(|v| (0.05354..0.5).contains(v)),
315 "When SCALE set to 1, ARG1 should be: 0.05354 <= ARG1 < 0.5"
316 ), 364 ),
317 Scale::A1o4_R4 => assert!( 365 Sqrt => assert!(
318 arg1s.iter().all(|v| (0.25..0.75).contains(v)), 366 (0..=2).contains(&(config.scale as u8)),
319 "When SCALE set to 2, ARG1 should be: 0.25 <= ARG1 < 0.75" 367 "SCALE should be: 0 <= SCALE <= 2"
320 ), 368 ),
321 Scale::A1o8_R8 => assert!( 369 }
322 arg1s.iter().all(|v| (0.375..0.875).contains(v)), 370
323 "When SCALE set to 3, ARG1 should be: 0.375 <= ARG1 < 0.875" 371 // check ARG1 value
372 match config.function {
373 Cos | Sin | Phase | Modulus | Arctan => {
374 assert!(
375 arg1s.iter().all(|v| (-1.0..=1.0).contains(v)),
376 "ARG1 should be: -1 <= ARG1 <= 1"
377 );
378 }
379
380 Cosh | Sinh => assert!(
381 arg1s.iter().all(|v| (-0.559..=0.559).contains(v)),
382 "ARG1 should be: -0.559 <= ARG1 <= 0.559"
324 ), 383 ),
325 Scale::A1o16_R16 => assert!( 384
326 arg1s.iter().all(|v| (0.4375f64..0.584f64).contains(v)), 385 Arctanh => assert!(
327 "When SCALE set to 4, ARG1 should be: 0.4375 <= ARG1 < 0.584" 386 arg1s.iter().all(|v| (-0.403..=0.403).contains(v)),
387 "ARG1 should be: -0.403 <= ARG1 <= 0.403"
328 ), 388 ),
329 _ => unreachable!(),
330 };
331 }
332 389
333 Function::Sqrt => match config.scale { 390 Ln => {
334 Scale::A1_R1 => assert!( 391 match config.scale {
335 arg1s.iter().all(|v| (0.027..0.75).contains(v)), 392 Scale::A1o2_R2 => assert!(
336 "When SCALE set to 0, ARG1 should be: 0.027 <= ARG1 < 0.75" 393 arg1s.iter().all(|v| (0.05354..0.5).contains(v)),
337 ), 394 "When SCALE set to 1, ARG1 should be: 0.05354 <= ARG1 < 0.5"
338 Scale::A1o2_R2 => assert!( 395 ),
339 arg1s.iter().all(|v| (0.375..0.875).contains(v)), 396 Scale::A1o4_R4 => assert!(
340 "When SCALE set to 1, ARG1 should be: 0.375 <= ARG1 < 0.875" 397 arg1s.iter().all(|v| (0.25..0.75).contains(v)),
341 ), 398 "When SCALE set to 2, ARG1 should be: 0.25 <= ARG1 < 0.75"
342 Scale::A1o4_R4 => assert!( 399 ),
343 arg1s.iter().all(|v| (0.4375..0.585).contains(v)), 400 Scale::A1o8_R8 => assert!(
344 "When SCALE set to 2, ARG1 should be: 0.4375 <= ARG1 < 0.585" 401 arg1s.iter().all(|v| (0.375..0.875).contains(v)),
345 ), 402 "When SCALE set to 3, ARG1 should be: 0.375 <= ARG1 < 0.875"
346 _ => unreachable!(), 403 ),
347 }, 404 Scale::A1o16_R16 => assert!(
348 } 405 arg1s.iter().all(|v| (0.4375..0.584).contains(v)),
406 "When SCALE set to 4, ARG1 should be: 0.4375 <= ARG1 < 0.584"
407 ),
408 _ => unreachable!(),
409 };
410 }
411
412 Function::Sqrt => match config.scale {
413 Scale::A1_R1 => assert!(
414 arg1s.iter().all(|v| (0.027..0.75).contains(v)),
415 "When SCALE set to 0, ARG1 should be: 0.027 <= ARG1 < 0.75"
416 ),
417 Scale::A1o2_R2 => assert!(
418 arg1s.iter().all(|v| (0.375..0.875).contains(v)),
419 "When SCALE set to 1, ARG1 should be: 0.375 <= ARG1 < 0.875"
420 ),
421 Scale::A1o4_R4 => assert!(
422 arg1s.iter().all(|v| (0.4375..0.585).contains(v)),
423 "When SCALE set to 2, ARG1 should be: 0.4375 <= ARG1 < 0.585"
424 ),
425 _ => unreachable!(),
426 },
427 }
349 428
350 // check ARG2 value 429 // check ARG2 value
351 if let Some(arg2s) = arg2s { 430 if let Some(arg2s) = arg2s {
352 match config.function { 431 match config.function {
353 Cos | Sin => assert!( 432 Cos | Sin => assert!(
354 arg2s.iter().all(|v| (0.0..=1.0).contains(v)), 433 arg2s.iter().all(|v| (0.0..=1.0).contains(v)),
355 "ARG2 should be: 0 <= ARG2 <= 1" 434 "ARG2 should be: 0 <= ARG2 <= 1"
356 ), 435 ),
357 436
358 Phase | Modulus => assert!( 437 Phase | Modulus => assert!(
359 arg2s.iter().all(|v| (-1.0..=1.0).contains(v)), 438 arg2s.iter().all(|v| (-1.0..=1.0).contains(v)),
360 "ARG2 should be: -1 <= ARG2 <= 1" 439 "ARG2 should be: -1 <= ARG2 <= 1"
361 ), 440 ),
362 441
363 _ => (), 442 _ => (),
443 }
444 }
364 } 445 }
365 } 446 }
366 } 447 };
367} 448}
368 449
450check_input_value!(check_input_f64, f64);
451check_input_value!(check_input_f32, f32);
452
369foreach_interrupt!( 453foreach_interrupt!(
370 ($inst:ident, cordic, $block:ident, GLOBAL, $irq:ident) => { 454 ($inst:ident, cordic, $block:ident, GLOBAL, $irq:ident) => {
371 impl Instance for peripherals::$inst { 455 impl Instance for peripherals::$inst {
diff --git a/embassy-stm32/src/cordic/utils.rs b/embassy-stm32/src/cordic/utils.rs
index 3f055c34b..2f4b5c5e8 100644
--- a/embassy-stm32/src/cordic/utils.rs
+++ b/embassy-stm32/src/cordic/utils.rs
@@ -3,7 +3,7 @@
3macro_rules! floating_fixed_convert { 3macro_rules! floating_fixed_convert {
4 ($f_to_q:ident, $q_to_f:ident, $unsigned_bin_typ:ty, $signed_bin_typ:ty, $float_ty:ty, $offset:literal, $min_positive:literal) => { 4 ($f_to_q:ident, $q_to_f:ident, $unsigned_bin_typ:ty, $signed_bin_typ:ty, $float_ty:ty, $offset:literal, $min_positive:literal) => {
5 /// convert float point to fixed point format 5 /// convert float point to fixed point format
6 pub fn $f_to_q(value: $float_ty) -> $unsigned_bin_typ { 6 pub(crate) fn $f_to_q(value: $float_ty) -> $unsigned_bin_typ {
7 const MIN_POSITIVE: $float_ty = unsafe { core::mem::transmute($min_positive) }; 7 const MIN_POSITIVE: $float_ty = unsafe { core::mem::transmute($min_positive) };
8 8
9 assert!( 9 assert!(
@@ -31,7 +31,7 @@ macro_rules! floating_fixed_convert {
31 31
32 #[inline(always)] 32 #[inline(always)]
33 /// convert fixed point to float point format 33 /// convert fixed point to float point format
34 pub fn $q_to_f(value: $unsigned_bin_typ) -> $float_ty { 34 pub(crate) fn $q_to_f(value: $unsigned_bin_typ) -> $float_ty {
35 // It's needed to convert from unsigned to signed first, for correct result. 35 // It's needed to convert from unsigned to signed first, for correct result.
36 -(value as $signed_bin_typ as $float_ty) / ((1 as $unsigned_bin_typ << $offset) as $float_ty) 36 -(value as $signed_bin_typ as $float_ty) / ((1 as $unsigned_bin_typ << $offset) as $float_ty)
37 } 37 }