kopia lustrzana https://github.com/kamocat/uSDX
Made progress on DMA for Speaker output
Considering switching to interrupt updater due to increased flexibilitychibios
rodzic
98a508629a
commit
dede6b7bef
|
@ -1,25 +1,23 @@
|
|||
#include "speaker.h"
|
||||
|
||||
/** Currently the strategy is to use DMA to transfer data
|
||||
* from a buffer to the PWM driver, updating every cycle.
|
||||
* However, this is impractical for several reasons:
|
||||
* 1, this makes the audio sample rate tied to the PWM top value,
|
||||
* meaning we can't pick an arbitrary sample rate
|
||||
* 2, a 16-bit PWM signal would have an update rate of 488Hz, effectively
|
||||
* generating a 900Hz tone that overpowers our audio. Obviously this is
|
||||
* undesirable. An 11-bit PWM signal could have an update rate of 15kHz,
|
||||
* meaning it generates a 30kHz tone. But to feed this with DMA, we would
|
||||
* have to upsample from 5kHz, taking up RAM with duplicate data.
|
||||
*
|
||||
* The simpler approach is to run a fast interrupt on a different timer,
|
||||
* allowing us to decouple the PWM generation from the audio sample rate.
|
||||
* Even with reduced audio output resolution, high input resolution still has
|
||||
* advantages like increased dynamic range and noise rejection.
|
||||
*/
|
||||
|
||||
static const DMAConfig spkr_dma = {
|
||||
.stream = STM32_ICU1_CH1_DMA_STREAM,
|
||||
.channel = STM32_ICU1_CH1_DMA_CHANNEL,
|
||||
.dma_priority = STM32_ICU1_CH1_DMA_PRIORITY,
|
||||
.irq_priority = STM32_ICU1_CH1_DMA_IRQ_PRIORITY,
|
||||
.periph_addr = &TIM3->DMAR,
|
||||
.direction = DMA_DIR_P2M,
|
||||
.psize = 2,
|
||||
.msize = 2,
|
||||
.inc_peripheral_addr = false,
|
||||
.inc_memory_addr = true,
|
||||
.circular = true,
|
||||
.error_cb = &error_cb,
|
||||
.end_cb = &end_cb,
|
||||
.mburst = 8,
|
||||
.fifo = 4
|
||||
};
|
||||
|
||||
//DMA channels is STM32_PWM_TIM3_DMA_STREAM
|
||||
uint16_t spkr_dma_buf[spkr_buffer_len];
|
||||
|
||||
void speakerUpdate(int16_t data, int len);
|
||||
|
||||
|
@ -33,7 +31,7 @@ void speaker_callback(PWMDriver * pwmp){
|
|||
static PWMConfig spkr = {
|
||||
.frequency = 4096000, /* 4MHz PWM clock frequency. */
|
||||
.period = 4096, /* Initial PWM period 1ms. */
|
||||
.callback = speaker_callback,
|
||||
.callback = NULL,
|
||||
.channels = {
|
||||
{PWM_OUTPUT_ACTIVE_HIGH, NULL},
|
||||
{PWM_OUTPUT_DISABLED, NULL},
|
||||
|
@ -44,10 +42,29 @@ static PWMConfig spkr = {
|
|||
.dier = STM32_TIM_DIER_CC1DE, // DMA request on channel 1 compare match
|
||||
};
|
||||
|
||||
const uint32_t dma_config = 0
|
||||
| STM32_DMA_CR_DIR_M2P // Memory to peripheral
|
||||
| STM32_DMA_CR_CIRC // Circular buffer
|
||||
| STM32_DMA_CR_MINC // Memory Increment Mode
|
||||
| STM32_DMA_CR_PSIZE_WORD // 16-bit peripheral space
|
||||
| STM32_DMA_CR_MSIZE_WORD // 16-bit buffer width in RAM
|
||||
| STM32_DMA_CR_PL(3) // High priority
|
||||
| STM32_DMA_CR_TCIE // Transfer Complete Interrupt
|
||||
| STM32_DMA_CR_HTIE // Half-transfer Interrupt
|
||||
;
|
||||
|
||||
void speakerStart(void){
|
||||
static stm32_dma_stream_t * stream =
|
||||
dmaStreamAlloc(STM32_PWM_TIM3_DMA_STREAM, 2, speaker_callback, NULL);
|
||||
dmaStreamSetPeripheral(stream, &TIM3->DMAR);
|
||||
dmaStreamSetMemory0(stream, spkr_dma_buf);
|
||||
dmaStreamSetTransactionSize(stream, spkr_buffer_len);
|
||||
dmaStreamSetMode(stream, dma_config);
|
||||
dmaStreamEnable(stream);
|
||||
pwmStart(&PWMD3, &spkr);
|
||||
}
|
||||
|
||||
void speakerStop(void){
|
||||
pwmStop(&PWMD3);
|
||||
dmaStreamDisable(stream);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "hal.h"
|
||||
#include <stdint.h>
|
||||
|
||||
const size_t spkr_buffer_len = 64;
|
||||
|
||||
void speakerStart(void);
|
||||
void speakerStop(void);
|
||||
|
|
Ładowanie…
Reference in New Issue