From c279397cba5c057501c46b4e97accd2c2898a5b7 Mon Sep 17 00:00:00 2001 From: Adam Greenwood-Byrne Date: Thu, 4 Mar 2021 21:38:51 +0000 Subject: [PATCH] Fixed restart bug in multi-core Breakout and librified audio (CPU and DMA) --- part11-breakout-smp/breakout.c | 9 ++- part11-breakout-smp/breakout.h | 2 +- part11-breakout-smp/breakout_snd.c | 94 ++------------------------- part11-breakout-smp/include/audio.h | 59 +++++++++++++++++ part11-breakout-smp/include/io.h | 1 + part11-breakout-smp/lib/audio.c | 99 +++++++++++++++++++++++++++++ 6 files changed, 172 insertions(+), 92 deletions(-) create mode 100644 part11-breakout-smp/include/audio.h create mode 100644 part11-breakout-smp/lib/audio.c diff --git a/part11-breakout-smp/breakout.c b/part11-breakout-smp/breakout.c index 1506e64..57b8188 100644 --- a/part11-breakout-smp/breakout.c +++ b/part11-breakout-smp/breakout.c @@ -156,10 +156,10 @@ void moveObject(volatile struct Object *object, int x, int y) const int ballradius = 15; const int paddlewidth = 80; -volatile unsigned char dir = 50; -volatile unsigned int numobjs = 0; +volatile unsigned char dir; +volatile unsigned int numobjs; -volatile struct Object *objects = (struct Object *)SAFE_ADDRESS; +volatile struct Object *objects = (struct Object *)HEAP_ADDRESS; volatile struct Object *ball; volatile struct Object *paddle; volatile struct Object *scoreboard; @@ -167,6 +167,9 @@ volatile struct Object *endgame; void breakout_init() { + numobjs = 0; + dir = 50; + initBricks(); initBall(); initPaddle(); diff --git a/part11-breakout-smp/breakout.h b/part11-breakout-smp/breakout.h index c94cf84..6d8fa8f 100644 --- a/part11-breakout-smp/breakout.h +++ b/part11-breakout-smp/breakout.h @@ -1,5 +1,5 @@ // Heap memory allocation -#define SAFE_ADDRESS 0x00400000 // Somewhere safe to store a lot of data +#define HEAP_ADDRESS 0x00400000 // Somewhere safe to store a lot of data // The screen #define WIDTH 1920 diff --git a/part11-breakout-smp/breakout_snd.c b/part11-breakout-smp/breakout_snd.c index 781c3d6..5c37405 100644 --- a/part11-breakout-smp/breakout_snd.c +++ b/part11-breakout-smp/breakout_snd.c @@ -1,77 +1,14 @@ -#include "include/fb.h" -#include "include/io.h" #include "include/multicore.h" - -#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 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 -#define BCM2711_PWM1_RANGE 8 -#define BCM2711_PWM1_DATA 9 - -#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 ERRORMASK (BCM2711_GAPO2 | BCM2711_GAPO1 | BCM2711_RERR1 | BCM2711_WERR1) - -volatile unsigned* clk = (void*)CLOCK_BASE; -volatile unsigned* pwm = (void*)PWM_BASE; - -void audio_init(void) -{ - gpio_useAsAlt0(40); // Ensure PWM1 is mapped to GPIO 40/41 - gpio_useAsAlt0(41); - wait_msec(2); - - // Setup clock - - *(clk + BCM2711_PWMCLK_CNTL) = PM_PASSWORD | (1 << 5); // Stop clock - wait_msec(2); - - int idiv = 2; - *(clk + BCM2711_PWMCLK_DIV) = PM_PASSWORD | (idiv<<12); - *(clk + BCM2711_PWMCLK_CNTL) = PM_PASSWORD | 16 | 1; // Osc + Enable - wait_msec(2); - - // Setup PWM - - *(pwm + BCM2711_PWM_CONTROL) = 0; - wait_msec(2); - - *(pwm+BCM2711_PWM0_RANGE) = 0x264; // 44.1khz, Stereo, 8-bit (54Mhz / 44100 / 2) - *(pwm+BCM2711_PWM1_RANGE) = 0x264; - - *(pwm+BCM2711_PWM_CONTROL) = - BCM2711_PWM1_USEFIFO | - BCM2711_PWM1_ENABLE | - BCM2711_PWM0_USEFIFO | - BCM2711_PWM0_ENABLE | 1<<6; -} +#include "include/audio.h" void snd_core(void) { clear_core2(); - int i=0; - long status; + // Initialise the audio + audio_init(); + + // Write data out to FIFO and loop infinitely extern unsigned char _binary_bin_audio_bin_start[]; extern unsigned char _binary_bin_audio_bin_size[]; @@ -79,24 +16,5 @@ void snd_core(void) unsigned int size = (long)&_binary_bin_audio_bin_size; unsigned char *data = &(_binary_bin_audio_bin_start[0]); - // Initialise the audio - audio_init(); - - // Write data out to FIFO and loop infinitely - - while (1) { - while (i < size) { - status = *(pwm + BCM2711_PWM_STATUS); - if (!(status & BCM2711_FULL1)) { - *(pwm+BCM2711_PWM_FIFO) = *(data + i); - i++; - *(pwm+BCM2711_PWM_FIFO) = *(data + i); - i++; - } - if ((status & ERRORMASK)) { - *(pwm+BCM2711_PWM_STATUS) = ERRORMASK; - } - } - i=0; - } + while (1) audio_play_cpu(data, size); } diff --git a/part11-breakout-smp/include/audio.h b/part11-breakout-smp/include/audio.h new file mode 100644 index 0000000..aa73d16 --- /dev/null +++ b/part11-breakout-smp/include/audio.h @@ -0,0 +1,59 @@ +#include "../include/io.h" + +#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 DMA_ADDRESS 0x00500000 /* A safe address to use for our DMA transfer */ + +#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 +#define BCM2711_PWM1_RANGE 8 +#define BCM2711_PWM1_DATA 9 + +#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 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 */ + +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))); + +void audio_init(void); +void audio_play_cpu(unsigned char *data, unsigned int size); +void audio_play_dma(unsigned char *data, unsigned int size); +void audio_wait_dma(void); diff --git a/part11-breakout-smp/include/io.h b/part11-breakout-smp/include/io.h index 5c8f2e4..dcc8dae 100644 --- a/part11-breakout-smp/include/io.h +++ b/part11-breakout-smp/include/io.h @@ -1,4 +1,5 @@ #define PERIPHERAL_BASE 0xFE000000 +#define LEGACY_BASE 0x7E000000 void uart_init(); void uart_writeText(char *buffer); diff --git a/part11-breakout-smp/lib/audio.c b/part11-breakout-smp/lib/audio.c new file mode 100644 index 0000000..23f8203 --- /dev/null +++ b/part11-breakout-smp/lib/audio.c @@ -0,0 +1,99 @@ +#include "../include/audio.h" +#include "../include/fb.h" + +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*)DMA_ADDRESS; +struct dma_cb playback_cb; + +void audio_init(void) +{ + gpio_useAsAlt0(40); // Ensure PWM1 is mapped to GPIO 40/41 + gpio_useAsAlt0(41); + wait_msec(2); + + // Setup clock + + *(clk + BCM2711_PWMCLK_CNTL) = PM_PASSWORD | (1 << 5); // Stop clock + wait_msec(2); + + int idiv = 2; + *(clk + BCM2711_PWMCLK_DIV) = PM_PASSWORD | (idiv<<12); + *(clk + BCM2711_PWMCLK_CNTL) = PM_PASSWORD | 16 | 1; // Osc + Enable + wait_msec(2); + + // Setup PWM + + *(pwm + BCM2711_PWM_CONTROL) = 0; + wait_msec(2); + + *(pwm+BCM2711_PWM0_RANGE) = 0x264; // 44.1khz, Stereo, 8-bit (54Mhz / 44100 / 2) + *(pwm+BCM2711_PWM1_RANGE) = 0x264; + + *(pwm+BCM2711_PWM_CONTROL) = + BCM2711_PWM1_USEFIFO | + BCM2711_PWM1_ENABLE | + BCM2711_PWM0_USEFIFO | + BCM2711_PWM0_ENABLE | 1<<6; +} + +void audio_play_cpu(unsigned char *data, unsigned int size) +{ + int i=0; + long status; + + // Write data out to FIFO + + while (i < size) { + status = *(pwm + BCM2711_PWM_STATUS); + if (!(status & BCM2711_FULL1)) { + *(pwm+BCM2711_PWM_FIFO) = *(data + i); + i++; + *(pwm+BCM2711_PWM_FIFO) = *(data + i); + i++; + } + if ((status & ERRORMASK)) { + *(pwm+BCM2711_PWM_STATUS) = ERRORMASK; + } + } +} + +void audio_play_dma(unsigned char *data, unsigned int size) +{ + // Convert data (we expect 8-bit samples, but need to convert them to 32-bit words) + + for (int i=0;i