From 4386a4ca3225b204059bfa82fd23423a3730432c Mon Sep 17 00:00:00 2001 From: Adam Greenwood-Byrne Date: Wed, 17 Feb 2021 23:40:03 +0000 Subject: [PATCH] PWM audio now works using either CPU or DMA in part9-sound demo --- part9-sound/README.md | 2 +- part9-sound/io.h | 2 + part9-sound/kernel.c | 121 +++++++++++++++++++++++++++++++++--------- 3 files changed, 99 insertions(+), 26 deletions(-) diff --git a/part9-sound/README.md b/part9-sound/README.md index 296ad35..6c09144 100644 --- a/part9-sound/README.md +++ b/part9-sound/README.md @@ -10,5 +10,5 @@ This code was derived from [Peter Lemon's work](https://github.com/PeterLemon/Ra Todo ---- * Write-up the CPU-driven `playaudio_cpu()` code, explaining clocks/PWM etc. - * Code the DMA version so we don't have to tie up the CPU + * Write-up the DMA version `playaudio_dma()` version, which doesn't tie up the CPU but still plays sound! * Add a Makefile.gcc (I'm using LLVM Clang these days, so not a priority) diff --git a/part9-sound/io.h b/part9-sound/io.h index 5c8f2e4..ff2fa98 100644 --- a/part9-sound/io.h +++ b/part9-sound/io.h @@ -1,4 +1,6 @@ #define PERIPHERAL_BASE 0xFE000000 +#define LEGACY_BASE 0x7E000000 +#define SAFE_ADDRESS 0x00400000 // Somewhere safe to store a lot of data void uart_init(); void uart_writeText(char *buffer); diff --git a/part9-sound/kernel.c b/part9-sound/kernel.c index 7c380ab..5522075 100644 --- a/part9-sound/kernel.c +++ b/part9-sound/kernel.c @@ -1,14 +1,19 @@ #include "fb.h" #include "io.h" -#define PWM_BASE (PERIPHERAL_BASE + 0x20C000 + 0x800) /* PWM1 register base address on RPi4 */ -#define CLOCK_BASE (PERIPHERAL_BASE + 0x101000) +#define PWM_BASE (PERIPHERAL_BASE + 0x20C000 + 0x800) /* PWM1 register base address on RPi4 */ +#define PWM_LEGACY_BASE (LEGACY_BASE + 0x20C000 + 0x800) /* PWM1 register base legacy address on RPi4 */ +#define CLOCK_BASE (PERIPHERAL_BASE + 0x101000) +#define DMA_BASE (PERIPHERAL_BASE + 0x007100) /* DMA register base address */ +#define DMA_ENABLE (DMA_BASE + 0xFF0) /* DMA global enable bits */ #define BCM2711_PWMCLK_CNTL 40 #define BCM2711_PWMCLK_DIV 41 +#define PM_PASSWORD 0x5A000000 #define BCM2711_PWM_CONTROL 0 #define BCM2711_PWM_STATUS 1 +#define BCM2711_PWM_DMAC 2 #define BCM2711_PWM0_RANGE 4 #define BCM2711_PWM0_DATA 5 #define BCM2711_PWM_FIFO 6 @@ -17,53 +22,109 @@ #define BCM2711_PWM1_USEFIFO 0x2000 /* Data from FIFO */ #define BCM2711_PWM1_ENABLE 0x0100 /* Channel enable */ - #define BCM2711_PWM0_USEFIFO 0x0020 /* Data from FIFO */ #define BCM2711_PWM0_ENABLE 0x0001 /* Channel enable */ +#define BCM2711_PWM_ENAB 0x80000000 /* PWM DMA Configuration: DMA Enable (bit 31 set) */ #define BCM2711_GAPO2 0x20 #define BCM2711_GAPO1 0x10 #define BCM2711_RERR1 0x8 #define BCM2711_WERR1 0x4 #define BCM2711_FULL1 0x1 - -#define PM_PASSWORD 0x5A000000 - #define ERRORMASK (BCM2711_GAPO2 | BCM2711_GAPO1 | BCM2711_RERR1 | BCM2711_WERR1) +#define DMA_CS 0 /* Control/status register offset for DMA channel 0 */ +#define DMA_CONBLK_AD 1 +#define DMA_EN1 1 << 1 /* Enable DMA engine 1 */ +#define DMA_ACTIVE 1 /* Active bit set */ +#define DMA_DEST_DREQ 0x40 /* Use DREQ to pace peripheral writes */ +#define DMA_PERMAP_1 0x10000 /* PWM1 peripheral for DREQ */ +#define DMA_SRC_INC 0x100 /* Increment source address */ + volatile unsigned* clk = (void*)CLOCK_BASE; volatile unsigned* pwm = (void*)PWM_BASE; +volatile unsigned* dma = (void*)DMA_BASE; +volatile unsigned* dmae = (void*)DMA_ENABLE; +volatile unsigned* safe = (void*)SAFE_ADDRESS; -static void audio_init(void) +struct dma_cb { + unsigned int ti; + unsigned int source_ad; + unsigned int dest_ad; + unsigned int txfr_len; + unsigned int stride; + unsigned int nextconbk; + unsigned int null1; + unsigned int null2; +} __attribute__((aligned(32))); + +struct dma_cb playback_cb; + +static void playaudio_dma(void) { - gpio_useAsAlt0(40); // Ensure PWM1 is mapped to GPIO 40/41 - gpio_useAsAlt0(41); + extern unsigned char _binary_audio_bin_start[]; + extern unsigned char _binary_audio_bin_size[]; + + unsigned int size = (long)&_binary_audio_bin_size; + unsigned char *data = &(_binary_audio_bin_start[0]); + + // Convert data + for (int i=0;i finished"); + + while(1); }