Made progress on DMA for Speaker output

Considering switching to interrupt updater due to increased flexibility
chibios
Marshal Horn 2020-07-16 23:41:08 -07:00
rodzic 98a508629a
commit dede6b7bef
2 zmienionych plików z 39 dodań i 20 usunięć

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -1,5 +1,7 @@
#include "hal.h"
#include <stdint.h>
const size_t spkr_buffer_len = 64;
void speakerStart(void);
void speakerStop(void);