13 #error Only the ESP32 supports ULP audio output
16 #include <driver/dac.h>
17 #include <driver/rtc_io.h>
18 #include <esp32/ulp.h>
24 enum UlpDac { ULP_DAC1 = 1, ULP_DAC2 = 2 };
44 selected_mono_dac = dac;
49 min_write_bytes = bytes;
57 activeDACs = stereoOutput ? 3 : selected_mono_dac;
67 size_t write(
const uint8_t *data,
size_t len) {
69 int16_t *data_16 = (int16_t *)data;
72 int frameSize = cfg.
channels *
sizeof(int16_t);
73 int frames = len / frameSize;
74 for (
int j = 0; j < frames; j++) {
76 stereo[0] = data_16[pos];
77 stereo[1] = stereoOutput ? data_16[pos + 1] : data_16[pos];
79 while (!writeFrame(stereo)) {
87 int availableForWrite() {
88 int result = totalSampleWords-lastFilledWord;
89 return result < min_write_bytes ? 0 : result;
94 const ulp_insn_t stopulp[] = {
100 size_t size =
sizeof(stopulp) /
sizeof(ulp_insn_t);
101 ulp_process_macros_and_load(load_addr, stopulp, &size);
106 if (activeDACs & 1) {
107 dac_output_voltage(DAC_CHANNEL_1, 128);
109 if (activeDACs & 2) {
110 dac_output_voltage(DAC_CHANNEL_2, 128);
116 int lastFilledWord = 0;
118 int min_write_bytes = 128;
119 UlpDac selected_mono_dac = ULP_DAC1;
120 uint8_t bufferedOddSample = 128;
121 bool waitingOddSample =
true;
123 bool stereoOutput =
true;
124 const int opcodeCount = 20;
125 const uint32_t dacTableStart1 = 2048 - 512;
126 const uint32_t dacTableStart2 = dacTableStart1 - 512;
127 uint32_t totalSampleWords =
128 2048 - 512 - 512 - (opcodeCount + 1);
129 const int totalSamples = totalSampleWords * 2;
130 const uint32_t indexAddress = opcodeCount;
131 const uint32_t bufferStart = indexAddress + 1;
136 waitingOddSample =
false;
142 unsigned long rtc_8md256_period = rtc_clk_cal(RTC_CAL_8MD256, 1000);
143 unsigned long rtc_fast_freq_hz =
144 1000000ULL * (1 << RTC_CLK_CAL_FRACT) * 256 / rtc_8md256_period;
147 if (activeDACs & 1) {
148 dac_output_enable(DAC_CHANNEL_1);
149 dac_output_voltage(DAC_CHANNEL_1, 128);
151 if (activeDACs & 2) {
152 dac_output_enable(DAC_CHANNEL_2);
153 dac_output_voltage(DAC_CHANNEL_2, 128);
157 int retAddress2 = 14;
159 int loopCycles = 134;
160 int loopHalfCycles1 = 90;
161 int loopHalfCycles2 = 44;
163 LOGI(
"Real RTC clock: %d", rtc_fast_freq_hz);
165 uint32_t dt = (rtc_fast_freq_hz / hertz) - loopCycles;
168 dt = (rtc_fast_freq_hz / hertz) - loopHalfCycles1;
169 dt2 = (rtc_fast_freq_hz / hertz) - loopHalfCycles2;
173 LOGI(
"dt2: %d", dt2);
175 const ulp_insn_t stereo[] = {
183 I_ST(R0, R3, indexAddress),
185 I_LD(R1, R0, bufferStart),
187 I_ANDI(R2, R1, 0x00ff),
191 I_ADDI(R2, R2, dacTableStart1),
198 I_ANDI(R2, R1, 0xff00),
200 I_RSHI(R2, R2, 8 - 1),
202 I_ADDI(R2, R2, dacTableStart2),
209 I_ST(R1, R0, indexAddress),
213 I_BGE(-16, totalSampleWords),
216 I_DELAY((
unsigned int)dt + 2),
222 size_t load_addr = 0;
223 size_t size =
sizeof(stereo) /
sizeof(ulp_insn_t);
224 ulp_process_macros_and_load(load_addr, stereo, &size);
230 switch (activeDACs) {
232 for (
int i = 0; i < 256; i++) {
233 RTC_SLOW_MEM[dacTableStart1 + i * 2] = create_I_WR_REG(
234 RTC_IO_PAD_DAC1_REG, 19, 26, i);
235 RTC_SLOW_MEM[dacTableStart1 + 1 + i * 2] =
236 create_I_BXI(retAddress1);
237 RTC_SLOW_MEM[dacTableStart2 + i * 2] = create_I_WR_REG(
238 RTC_IO_PAD_DAC1_REG, 19, 26, i);
239 RTC_SLOW_MEM[dacTableStart2 + 1 + i * 2] =
240 create_I_BXI(retAddress2);
244 for (
int i = 0; i < 256; i++) {
245 RTC_SLOW_MEM[dacTableStart1 + i * 2] = create_I_WR_REG(
246 RTC_IO_PAD_DAC2_REG, 19, 26, i);
247 RTC_SLOW_MEM[dacTableStart1 + 1 + i * 2] =
248 create_I_BXI(retAddress1);
249 RTC_SLOW_MEM[dacTableStart2 + i * 2] = create_I_WR_REG(
250 RTC_IO_PAD_DAC2_REG, 19, 26, i);
251 RTC_SLOW_MEM[dacTableStart2 + 1 + i * 2] =
252 create_I_BXI(retAddress2);
256 for (
int i = 0; i < 256; i++) {
257 RTC_SLOW_MEM[dacTableStart1 + i * 2] = create_I_WR_REG(
258 RTC_IO_PAD_DAC1_REG, 19, 26, i);
259 RTC_SLOW_MEM[dacTableStart1 + 1 + i * 2] =
260 create_I_BXI(retAddress1);
261 RTC_SLOW_MEM[dacTableStart2 + i * 2] = create_I_WR_REG(
262 RTC_IO_PAD_DAC1_REG, 19, 26, i);
263 RTC_SLOW_MEM[dacTableStart2 + 1 + i * 2] =
264 create_I_BXI(retAddress2);
270 for (
int i = 0; i < totalSampleWords; i++)
271 RTC_SLOW_MEM[bufferStart + i] = 0x8080;
274 RTC_SLOW_MEM[indexAddress] = 0;
279 while (RTC_SLOW_MEM[indexAddress] == 0)
285 bool writeFrame(int16_t sample[2]) {
293 int currentSample = RTC_SLOW_MEM[indexAddress] & 0xffff;
294 int currentWord = currentSample >> 1;
296 for (
int i = 0; i < 2; i++) {
297 ms[i] = ((ms[i] >> 8) + 128) & 0xff;
301 (uint16_t)(((uint32_t)((int32_t)(ms[0]) + (int32_t)(ms[1])) >> 1) &
304 if (waitingOddSample) {
306 if (lastFilledWord !=
315 w = bufferedOddSample;
317 bufferedOddSample = 128;
318 waitingOddSample =
false;
320 RTC_SLOW_MEM[bufferStart + lastFilledWord] = w;
322 if (lastFilledWord == totalSampleWords)
329 bufferedOddSample = ms[0];
330 waitingOddSample =
true;
335 uint32_t create_I_WR_REG(uint32_t reg, uint32_t low_bit, uint32_t high_bit,
341 const ulp_insn_t singleinstruction[] = {
342 I_WR_REG(reg, low_bit, high_bit, val)};
343 ulp_union recover_ins;
344 recover_ins.ulp_ins = singleinstruction[0];
345 return (uint32_t)(recover_ins.ulp_bin);
348 uint32_t create_I_BXI(uint32_t imm_pc) {
353 const ulp_insn_t singleinstruction[] = {I_BXI(imm_pc)};
354 ulp_union recover_ins;
355 recover_ins.ulp_ins = singleinstruction[0];
356 return (uint32_t)(recover_ins.ulp_bin);