Skip to content

Commit

Permalink
Merge pull request #34 from emeb/master
Browse files Browse the repository at this point in the history
Add Audio DAC example
  • Loading branch information
cnlohr committed Apr 12, 2023
2 parents a22976b + bc27534 commit 3295854
Show file tree
Hide file tree
Showing 9 changed files with 612 additions and 0 deletions.
2 changes: 2 additions & 0 deletions examples/spi_dac/.gdbinit
@@ -0,0 +1,2 @@
file tim1_pwm.elf
target extended-remote localhost:3333
48 changes: 48 additions & 0 deletions examples/spi_dac/Makefile
@@ -0,0 +1,48 @@
TARGET:=spi_dac

all : flash

PREFIX:=riscv64-unknown-elf

GPIO_Toggle:=EXAM/GPIO/GPIO_Toggle/User

CH32V003FUN:=../../ch32v003fun
MINICHLINK:=../../minichlink

ifeq ($(OS),Windows_NT)
# On Windows, all the major RISC-V GCC installs are missing the -ec libgcc.
LIB_GCC=../../misc/libgcc.a
else
LIB_GCC=-lgcc
endif

CFLAGS:= \
-g -Os -flto -ffunction-sections \
-static-libgcc $(LIB_GCC) \
-march=rv32ec \
-mabi=ilp32e \
-I/usr/include/newlib \
-I$(CH32V003FUN) \
-nostdlib \
-I. -DSTDOUT_UART -Wall

LDFLAGS:=-T $(CH32V003FUN)/ch32v003fun.ld -Wl,--gc-sections

SYSTEM_C:=$(CH32V003FUN)/ch32v003fun.c

$(TARGET).elf : $(SYSTEM_C) $(TARGET).c
$(PREFIX)-gcc -o $@ $^ $(CFLAGS) $(LDFLAGS)

$(TARGET).bin : $(TARGET).elf
$(PREFIX)-size $^
$(PREFIX)-objdump -S $^ > $(TARGET).lst
$(PREFIX)-objdump -t $^ > $(TARGET).map
$(PREFIX)-objcopy -O binary $< $(TARGET).bin
$(PREFIX)-objcopy -O ihex $< $(TARGET).hex

flash : $(TARGET).bin
$(MINICHLINK)/minichlink -w $< flash -b

clean :
rm -rf $(TARGET).elf $(TARGET).bin $(TARGET).hex $(TARGET).lst $(TARGET).map $(TARGET).hex

54 changes: 54 additions & 0 deletions examples/spi_dac/README.md
@@ -0,0 +1,54 @@
# SPI DAC Demo
This example shows how to set up the SPI port with a timer, circular DMA and
IRQs to do continuous audio output through an inexpensive I2S DAC.

![Scope image of sine and sawtooth waves](oscope.png)

## Theory
The CH32V003 does not have an I2S port which is usually required for driving
audio DACs, but the inexpensive PT8211 stereo audio DAC is very forgiving of
the signal format used to drive it so we can approximate an I2S signal using
one of the CH32V003 on-chip timers to generate the frame sync signal. The SPI
port then provides the bit clock and serial data.

### Timer setup
TIM1 on the CH32V003 is set up to generate a 48kHz square wave which is output
on GPIO pin PC4 and serves as the frame sync or WS. The timer is configured to
run in center-aligned mode 3 which generates DMA requests on both rising and
falling edges. Channel 4 is configured as the output and the threshold is set
to 50% and the overall period is set to 48kHz.

### SPI setup
SPI1 is configured for 16-bit TX with a bit clock of 48MHz/8 (3MHz) which is
fast enough to clock out 16 bits of data between the edges of the frame sync
signal. Transmit data arrives via DMA, but the SPI port does not control DMA -
that is triggered from the timer above.

### DMA setup
DMA1 channel 4 is used because that channel is connected to TIM1 Chl 4 output
and is set up in circular mode with both Half-transfer and Transfer-Complete
interrupts. It continuously pulls data out of a 32-word buffer and sends it to
the SPI port when the timer fires.

### Interrupts
The DMA TC and HT IRQs trigger execution of a buffer fill routine which simply
indexes through a sinewave table at variable rates using fixed-point math to
fill the buffer as requested. This process uses up only about 4% of the
available CPU cycles so there's plenty leftover for foreground processing or
more complex waveform calculations like interpolation or synthesis.

## Use
Connect a PT8211 DAC as follows:
* DAC pin 1 (BCK) - MCU pin 15 (PC5/SCK)
* DAC pin 2 (WS) - MCU pin 14 (PC4/T1CH4)
* DAC pin 3 (DIN) - MCU pin 16 {PC6/MOSI)
* DAC pin 4 (GND) - ground
* DAC pin 5 (VCC) - 3.3V or 5V supply
* DAC pin 6 (LCH) - left channel output
* DAC pin 8 (RCH) - right channel output

![Schematic of SPI DAC hookup](spi_dac_schem.png)

Connect an oscilloscope to the left and right channel outputs and observe a
sine waveform at 187Hz on the right channel output and a sawtooth wave at
47Hz on the left channel output.
259 changes: 259 additions & 0 deletions examples/spi_dac/Sine16bit.h
@@ -0,0 +1,259 @@
/* Sinewave LUT */
const int16_t Sine16bit[256] = {
0,
804,
1608,
2410,
3212,
4011,
4808,
5602,
6393,
7179,
7962,
8739,
9512,
10278,
11039,
11793,
12539,
13279,
14010,
14732,
15446,
16151,
16846,
17530,
18204,
18868,
19519,
20159,
20787,
21403,
22005,
22594,
23170,
23731,
24279,
24811,
25329,
25832,
26319,
26790,
27245,
27683,
28105,
28510,
28898,
29268,
29621,
29956,
30273,
30571,
30852,
31113,
31356,
31580,
31785,
31971,
32137,
32285,
32412,
32521,
32609,
32678,
32728,
32757,
32767,
32757,
32728,
32678,
32609,
32521,
32412,
32285,
32137,
31971,
31785,
31580,
31356,
31113,
30852,
30571,
30273,
29956,
29621,
29268,
28898,
28510,
28105,
27683,
27245,
26790,
26319,
25832,
25329,
24811,
24279,
23731,
23170,
22594,
22005,
21403,
20787,
20159,
19519,
18868,
18204,
17530,
16846,
16151,
15446,
14732,
14010,
13279,
12539,
11793,
11039,
10278,
9512,
8739,
7962,
7179,
6393,
5602,
4808,
4011,
3212,
2410,
1608,
804,
0,
-804,
-1608,
-2410,
-3212,
-4011,
-4808,
-5602,
-6393,
-7179,
-7962,
-8739,
-9512,
-10278,
-11039,
-11793,
-12539,
-13279,
-14010,
-14732,
-15446,
-16151,
-16846,
-17530,
-18204,
-18868,
-19519,
-20159,
-20787,
-21403,
-22005,
-22594,
-23170,
-23731,
-24279,
-24811,
-25329,
-25832,
-26319,
-26790,
-27245,
-27683,
-28105,
-28510,
-28898,
-29268,
-29621,
-29956,
-30273,
-30571,
-30852,
-31113,
-31356,
-31580,
-31785,
-31971,
-32137,
-32285,
-32412,
-32521,
-32609,
-32678,
-32728,
-32757,
-32767,
-32757,
-32728,
-32678,
-32609,
-32521,
-32412,
-32285,
-32137,
-31971,
-31785,
-31580,
-31356,
-31113,
-30852,
-30571,
-30273,
-29956,
-29621,
-29268,
-28898,
-28510,
-28105,
-27683,
-27245,
-26790,
-26319,
-25832,
-25329,
-24811,
-24279,
-23731,
-23170,
-22594,
-22005,
-21403,
-20787,
-20159,
-19519,
-18868,
-18204,
-17530,
-16846,
-16151,
-15446,
-14732,
-14010,
-13279,
-12539,
-11793,
-11039,
-10278,
-9512,
-8739,
-7962,
-7179,
-6393,
-5602,
-4808,
-4011,
-3212,
-2410,
-1608,
-804
};
5 changes: 5 additions & 0 deletions examples/spi_dac/debug.sh
@@ -0,0 +1,5 @@
#!/bin/bash
# before running this you should start OOCD server
#../../../MRS_Toolchain_Linux_x64_V1.70/OpenOCD/bin/openocd -f ../../../MRS_Toolchain_Linux_x64_V1.70/OpenOCD/bin/wch-riscv.cfg

../../../MRS_Toolchain_Linux_x64_V1.70/RISC-V\ Embedded\ GCC/bin/riscv-none-embed-gdb
Binary file added examples/spi_dac/oscope.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 3295854

Please sign in to comment.