diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..c375a3a --- /dev/null +++ b/Readme.md @@ -0,0 +1,60 @@ +FARTrx +====== + +RX Path +------- +- Timer 1 runs continuously at 8khz. +- The HALs `pwm_hz` function is used to set up the timer, + as it is easier than setting the registers manually, + and we need the comparator match event to trigger the ADC. +- ADC conversions are triggered externally at each comparator match for Timer1 Channel1 +- ADC runs ins Scan-mode, it samples PA2 first, then PA3 +- DMA2 is set up to for device to memory, with memory increment, + transfer complete interrupt and double buffering disabled. + - The HAL requires the DMA transfer instance to take ownership of both buffers, + for the double buffered mode, to swap to the second buffer immediately, + once the first on is full. This means it would effectively require three buffers, + on to write to, one as a followup buffer and third one that's read by the program. + However, we can get away without double buffering, keeping the code a lot simpler. + There are 1/8kHz = 125uS between firing the transfer complete interrupt + once the first buffer is full and the next ADC conversion. + That's enough time swap buffers in the interrupt handler. +- In the DMA transfer complete interrupt the full buffer is moved out of the DMA transfer, + and replaced by the second buffer, so that the DSP code work on the full one. + - The buffer contains 128 alternating 16 bit wide samples from PA2 and PA3. + - An exponentionally smoothed average is used to remove the DC offset + - The samples are scaled by 2**10 and turned into an array of 128 complex numbers. + - A FIR-filter for filtering out the sideband is applied to the array + - The resulting audio is stored in the output buffer +- DMA1 is set up to transfer the output buffer into CCR3 of Timer4 + - Similar to the ADC two buffers are used alternating. + they are swapped out in the transfer complete interrupt. +- Timer4 is set up to output PWM on Channel3 on PB8 + - A new DMA Transfer is triggered on each channel 3 comparator match. + Actually the transfer should be triggered on each update event. + Unfortunately this does not seem to work reliably (probably a timing issue). + - Using DMA for PWM is not that well support in the HAL just yet, + so it requires some manually setup register and some unsafe code. + + +TX Path +------- +- Timer 1 runs continuously at 8khz. +- The HALs `pwm_hz` function is used to set up the timer, + as it is easier than setting the registers manually, + and we need the comparator match event to trigger the ADC. +- ADC conversions are triggered externally at each comparator match for Timer1 Channel1 +- ADC runs ins Scan-mode, to keep it easier to switch between RX and TX + - Scan sequence only contains PA4, the microphone input +- DMA2 is set up to for device to memory, with memory increment, + transfer complete interrupt and double buffering disabled. +- In the DMA transfer complete interrupt the full buffer is moved out of the DMA transfer, + and replaced by the second buffer, so that the DSP code work on the full one. + - The buffer contains 128 16bit wide audio samples + - An exponentionally smoothed average is used to remove the DC offset + - The samples are scaled by 2**10 and turned into an array of 128 complex numbers, + by extending them with a zero imaginary part. This results into a double sideband signal. +-TODO: + - Extracting the amplitude and dominant frequency + - Predistorted the amplitudes using a LUT, to compensate for non-linearities of the MOSFETs + - Setup DMA transfers for I2C and bias PWM \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index b2f2811..1cdb1fb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -219,7 +219,7 @@ mod app { unsafe { (*TIM4::ptr()).dier.modify(|_, w| { w.tde().set_bit(); // enable DMA trigger - w.cc3de().set_bit(); // dma on Update + w.cc3de().set_bit(); // dma on comperator match w }); };