|
| 1 | +#![deny(warnings)] |
| 2 | +#![deny(unsafe_code)] |
| 3 | +#![no_main] |
| 4 | +#![no_std] |
| 5 | + |
| 6 | +use cortex_m::asm::wfi; |
| 7 | +use hal::prelude::*; |
| 8 | +use hal::stm32; |
| 9 | +use stm32g4xx_hal as hal; |
| 10 | + |
| 11 | +use cortex_m_rt::entry; |
| 12 | + |
| 13 | +#[macro_use] |
| 14 | +mod utils; |
| 15 | + |
| 16 | +use utils::logger::info; |
| 17 | + |
| 18 | +use stm32g4xx_hal::fmac::{ |
| 19 | + buffer::{BufferLayout, Watermark}, |
| 20 | + function::IIR, |
| 21 | + Buffer, FmacExt, |
| 22 | +}; |
| 23 | + |
| 24 | +use fixed::types::I1F15; |
| 25 | + |
| 26 | +#[entry] |
| 27 | +fn main() -> ! { |
| 28 | + utils::logger::init(); |
| 29 | + |
| 30 | + info!("start"); |
| 31 | + let dp = stm32::Peripherals::take().expect("cannot take peripherals"); |
| 32 | + let mut rcc = dp.RCC.constrain(); |
| 33 | + |
| 34 | + // The FMAC has an internal memory area of 256x16bit words that must be allocated to the |
| 35 | + // three different buffers named X1 (input buffer), X2 (coefficients), and Y (output buffer). |
| 36 | + // |
| 37 | + // The BufferLayout struct takes three generic consts and will calculate the base offsets at compile time, |
| 38 | + // which must be passed as a generic parameter to the constrain method of the FMAC instance. |
| 39 | + // |
| 40 | + // Create an FMAC instance with a memory layout of 16 inputs, 2 coefficients, and 8 output buffer words |
| 41 | + // |
| 42 | + // For IIR filters, RM0440 indicates X2 coeffecient buffer should be 2N + 2M where |
| 43 | + // N is the number of feedforward coefficients and M is the number of feedback coefficients. |
| 44 | + // |
| 45 | + // Following constrain(), the buffer layout has been applied to the peripheral and cannot be changed. |
| 46 | + let mut fmac = dp |
| 47 | + .FMAC |
| 48 | + .constrain::<BufferLayout<32, 4, 1>>(&mut rcc) |
| 49 | + .reset(); |
| 50 | + |
| 51 | + // Configure an IIR filter with 1 feedforward, and 1 feedback coefficient, |
| 52 | + // with both coefficients set to 1.0. |
| 53 | + // |
| 54 | + // This is equivalent to a multiply accumulate operation |
| 55 | + // Y[n] = ∑ X1[n] * X2[0] + Y[n-1] * X2[1] |
| 56 | + // |
| 57 | + // The inputs will be set to ~0.01 (to nearest fixed point representation), and the output will increment |
| 58 | + // by 0.01 into Y for each input sample, and the final read of Y should be about 0.319 |
| 59 | + |
| 60 | + // Fill the input buffer with 0.01 |
| 61 | + fmac.preload_buffer(Buffer::X1, |_index| I1F15::from_num(0.01)); |
| 62 | + |
| 63 | + // Fill the coefficients with I1F15::MAX (max value representable by I1F15, ~1.0) |
| 64 | + fmac.preload_buffer(Buffer::X2, |_index| I1F15::MAX); |
| 65 | + fmac.preload_buffer(Buffer::Y, |_index| I1F15::ZERO); |
| 66 | + |
| 67 | + // Watermarks can be set on the X1 and Y buffers |
| 68 | + // to control when the input empty and output full |
| 69 | + // flags are asserted to cause early interrupts or DMA |
| 70 | + // to avoid underflow or overflow conditions. |
| 71 | + fmac.set_watermark(Buffer::X1, Watermark::Threshold1); |
| 72 | + fmac.set_watermark(Buffer::Y, Watermark::Threshold1); |
| 73 | + |
| 74 | + // Select the IIR function, sepecifying the number of |
| 75 | + // feedforward and feedback coefficients, and the gain |
| 76 | + fmac.select_function(IIR { |
| 77 | + feedforward_coeffs: 1, |
| 78 | + feedback_coeffs: 1, |
| 79 | + gain: 0, |
| 80 | + }); |
| 81 | + |
| 82 | + let fmac = fmac.start(); |
| 83 | + |
| 84 | + info!("Input buffer full: {}", fmac.is_input_full()); |
| 85 | + |
| 86 | + info!("Waiting for result"); |
| 87 | + while !fmac.is_result_available() {} |
| 88 | + |
| 89 | + info!("Reading results"); |
| 90 | + |
| 91 | + let mut count = 0; |
| 92 | + loop { |
| 93 | + while let Some(output) = fmac.read() { |
| 94 | + count += 1; |
| 95 | + info!("Output {}: {}", count, output.to_num::<f32>()); |
| 96 | + } |
| 97 | + } |
| 98 | +} |
0 commit comments