From be757025eb8625cbf83abcc1c9c905bcbba2391c Mon Sep 17 00:00:00 2001 From: Andrew McPherson Date: Thu, 8 Aug 2019 18:08:24 +0100 Subject: [PATCH 001/148] Support TDM mode on TLV codec: now working in 256-clock mode with either 16 or 32 bit slots (was 1221974f..f43f7587 and removed trailing whitespaces) --- core/I2c_Codec.cpp | 125 +++++++++++++++++++++++++++++++++++++------- core/PRU.cpp | 3 +- include/I2c_Codec.h | 6 +++ pru/pru_rtaudio.p | 106 +++++++++++++++++++++++++++++++++---- 4 files changed, 210 insertions(+), 30 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index f1d4c6a02..291254540 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -15,8 +15,11 @@ #include "../include/I2c_Codec.h" #define TLV320_DSP_MODE +#define TLV320_256CLOCK_MODE + I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, bool isVerbose /*= false*/) -: dacVolumeHalfDbs(0), adcVolumeHalfDbs(0), hpVolumeHalfDbs(0), running(false) +: dacVolumeHalfDbs(0), adcVolumeHalfDbs(0), hpVolumeHalfDbs(0), + slotSize(16), slotOffset(0), master(true), running(false) { setVerbose(isVerbose); initI2C_RW(i2cBus, i2cAddress, -1); @@ -44,6 +47,13 @@ int I2c_Codec::initCodec() // it runs at 44.1kHz int I2c_Codec::startAudio(int dual_rate) { + return startAudio(dual_rate, 1); +} + +int I2c_Codec::startAudio(int dual_rate, int is_master) +{ + master = is_master; + // As a best-practice it's safer not to assume the implementer has issued initCodec() // or has not otherwise modified codec registers since that call. // Explicit Switch to config register page 0: @@ -53,18 +63,30 @@ int I2c_Codec::startAudio(int dual_rate) // see datasehet for TLV320AIC3104 from page 44 if(writeRegister(0x02, 0x00)) // Codec sample rate register: fs_ref / 1 return 1; - // The sampling frequency is given as f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P) - // The master clock PLLCLK_IN is 12MHz - // K can be varied in intervals of resolution of 0.0001 up to 63.9999 - // using P=8 and R=1 gives a resolution of 0.0732421875Hz ( 0.000166% at 44.1kHz) - // to obtain Fs=44100 we need to have K=60.2112 - if(setPllP(8)) - return 1; - if(setPllR(1)) - return 1; - if(setAudioSamplingRate(44100)) //this will automatically find and set K for the given P and R so that Fs=44100 - return 1; + if(is_master) { + // The sampling frequency is given as f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P) + // The master clock PLLCLK_IN is 12MHz + // K can be varied in intervals of resolution of 0.0001 up to 63.9999 + // using P=8 and R=1 gives a resolution of 0.0732421875Hz ( 0.000166% at 44.1kHz) + // to obtain Fs=44100 we need to have K=60.2112 + + if(setPllP(8)) + return 1; + if(setPllR(1)) + return 1; + if(setAudioSamplingRate(44100)) //this will automatically find and set K for the given P and R so that Fs=44100 + return 1; + + // TODO: check if anything needs to change for 256 clock mode + } + else { + // Disable PLL: the codec will be clocked from the bit clock generated by another master + + if(writeRegister(0x03, 0x11)) // PLL disable, Q = 2 (fs = CLKIN / 256) + return 1; + } + if(dual_rate) { if(writeRegister(0x07, 0xEA)) // Codec datapath register: 44.1kHz; dual rate; standard datapath return 1; @@ -73,8 +95,34 @@ int I2c_Codec::startAudio(int dual_rate) if(writeRegister(0x07, 0x8A)) // Codec datapath register: 44.1kHz; std rate; standard datapath return 1; } - if(writeRegister(0x08, 0xC0)) // Audio serial control register A: BLCK, WCLK outputs + + if(is_master) { + if(writeRegister(0x08, 0xC0)) // Audio serial control register A: BLCK, WCLK outputs + return 1; + } + else { + if(writeRegister(0x08, 0x00)) // Audio serial control register A: BLCK, WCLK inputs + return 1; + } + +#ifdef TLV320_256CLOCK_MODE // for multi-codec mode + unsigned int crb; // Audio serial control register B + if(slotSize == 16) + crb = 0x48; + else if(slotSize == 20) + crb = 0x58; + else if(slotSize == 24) + crb = 0x68; + else if(slotSize == 32) + crb = 0x78; + else + return 1; + + if(writeRegister(0x09, crb)) // Audio serial control register B: DSP mode, word len specified by slotSize + return 1; + if(writeRegister(0x0A, slotOffset*slotSize)) // Audio serial control register C: offset of 16 bits per slot return 1; +#else #ifdef TLV320_DSP_MODE // to use with old PRU code if(writeRegister(0x09, 0x40)) // Audio serial control register B: DSP mode, word len 16 bits #else @@ -87,6 +135,8 @@ int I2c_Codec::startAudio(int dual_rate) if(writeRegister(0x0A, 0x01)) // Audio serial control register C: 1 bit offset #endif return 1; +#endif // TLV320_256CLOCK_MODE + if(writeRegister(0x0D, 0x00)) // Headset / button press register A: disabled return 1; if(writeRegister(0x0E, 0x00)) // Headset / button press register B: disabled @@ -105,8 +155,14 @@ int I2c_Codec::startAudio(int dual_rate) if(writeHPVolumeRegisters()) // Send DAC to high-power outputs return 1; - if(writeRegister(0x66, 0x02)) // Clock generation control register: use MCLK, PLL N = 2 - return 1; + if(is_master) { + if(writeRegister(0x66, 0x02)) // Clock generation control register: use MCLK, PLL N = 2 + return 1; + } + else { + if(writeRegister(0x66, 0x82)) // Clock generation control register: use BCLK, PLL N = 2 + return 1; + } //Set-up hardware high-pass filter for DC removal if(configureDCRemovalIIR()) @@ -114,6 +170,7 @@ int I2c_Codec::startAudio(int dual_rate) if(writeRegister(25, 0b10000000)) // Enable mic bias 2.5V return 1; + // TODO: may need to separate the code below for non-master codecs so they enable amps after the master clock starts // wait for the codec to stabilize before unmuting the HP amp. // this gets rid of the loud pop. @@ -129,8 +186,14 @@ int I2c_Codec::startAudio(int dual_rate) if(writeDACVolumeRegisters(false)) // Unmute and set volume return 1; - if(writeRegister(0x65, 0x00)) // GPIO control register B: disabled; codec uses PLLDIV_OUT - return 1; + if(is_master) { + if(writeRegister(0x65, 0x00)) // GPIO control register B: disabled; codec uses PLLDIV_OUT + return 1; + } + else { + if(writeRegister(0x65, 0x01)) // GPIO control register B: disabled; codec uses CLKDIV_OUT + return 1; + } if(writeADCVolumeRegisters(false)) // Unmute and set ADC volume return 1; @@ -221,6 +284,24 @@ int I2c_Codec::configureDCRemovalIIR(){ return 0; } +// Set the size of the I2S/DSP/TDM slots in bits +int I2c_Codec::setSlotSize(unsigned int size) { + if(size != 16 && size != 20 && size != 24 && size != 32) + return 1; + + slotSize = size; + return 0; +} + +// Set the slot in an 8-cycle TDM format where the first channel should be read (slot ranges from 0 to 7) +int I2c_Codec::setFirstTDMSlot(unsigned int slot) { + if(slot > 7) + return 1; + + slotOffset = slot; + return 0; +} + //set the numerator multiplier for the PLL int I2c_Codec::setPllK(float k){ short unsigned int j=(int)k; @@ -542,8 +623,14 @@ int I2c_Codec::disable(){ return 1; if(writeRegister(0x01, 0x80)) // Reset codec to defaults return 1; - if (writeRegister(0x08, 0xE0)) // Put codec in master mode (required for hi-z mode) - return 1; + if(master) { + if (writeRegister(0x08, 0xE0)) // Put codec in master mode (required for hi-z mode) + return 1; + } + else { + if (writeRegister(0x08, 0x00)) // Leave codec in slave mode + return 1; + } if(writeRegister(0x03, 0x11)) // PLL register A: disable return 1; if (writeRegister(0x24, 0x44)) // Power down left and right ADC diff --git a/core/PRU.cpp b/core/PRU.cpp index 722fb4591..eab67ca24 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -203,6 +203,7 @@ class PruMemory #define PRU_BUFFER_SPI_FRAMES 15 #define PRU_BOARD_FLAGS 16 #define PRU_ERROR_OCCURRED 17 +#define PRU_ACTIVE_TDM_SLOTS 18 // error codes sent from the PRU #define ARM_ERROR_TIMEOUT 1 @@ -622,7 +623,7 @@ void PRU::initialisePruCommon() pru_buffer_comm[PRU_SYNC_PIN_MASK] = 0; pru_buffer_comm[PRU_PRU_NUMBER] = pru_number; pru_buffer_comm[PRU_ERROR_OCCURRED] = 0; - + pru_buffer_comm[PRU_ACTIVE_TDM_SLOTS] = 2; // Default value; TODO: make this adjustable /* Set up multiplexer info */ if(context->multiplexerChannels == 2) { diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index 6b4b1dd70..a3562bfc2 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -31,8 +31,11 @@ class I2c_Codec : public I2c, public AudioCodec int initCodec(); int startAudio(int dual_rate); + int startAudio(int dual_rate, int is_master); int stopAudio(); + int setSlotSize(unsigned int size); + int setFirstTDMSlot(unsigned int slot); int setPllJ(short unsigned int j); int setPllD(unsigned int d); int setPllP(short unsigned int p); @@ -68,6 +71,9 @@ class I2c_Codec : public I2c, public AudioCodec int dacVolumeHalfDbs; int adcVolumeHalfDbs; int hpVolumeHalfDbs; + int slotSize; + int slotOffset; + bool master; bool running; bool verbose; bool hpEnabled; diff --git a/pru/pru_rtaudio.p b/pru/pru_rtaudio.p index 43dc5a899..db9b969e3 100644 --- a/pru/pru_rtaudio.p +++ b/pru/pru_rtaudio.p @@ -99,6 +99,7 @@ #define COMM_BUFFER_SPI_FRAMES 60 // Unused (used in pru_rtaudio_irq.p) #define COMM_BOARD_FLAGS 64 // Flags for the board we are on (BOARD_FLAGS_... are defined in include/PruBoardFlags.h) #define PRU_ERROR_OCCURRED 68 // Unused here +#define COMM_ACTIVE_TDM_SLOTS 72 // How many TDM slots contain useful data // General constants for McASP peripherals (used for audio codec) #define MCASP0_BASE 0x48038000 @@ -191,8 +192,58 @@ #define MCASP_OUTPUT_PINS (1 << 3) // Which pins are outputs #endif +#define MCASP_SLOT_16BITS + +#ifdef MCASP_SLOT_16BITS #define MCASP_DATA_MASK 0xFFFF // 16 bit data -#define MCASP_DATA_FORMAT 0x807C // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits +#endif + +#ifdef MCASP_SLOT_20BITS +#define MCASP_DATA_MASK 0xFFFFF // 20 bit data +#endif + +#ifdef MCASP_SLOT_24BITS +#define MCASP_DATA_MASK 0xFFFFFF // 24 bit data +#endif + +#ifdef MCASP_SLOT_32BITS +#define MCASP_DATA_MASK 0xFFFFFFFF // 32 bit data +#endif + +#define TLV320_MODE_TDM + +#ifdef TLV320_MODE_I2S +#define MCASP_AFSCTL_VALUE 0x101 // 2-slot TDM I2S mode, falling edge means beginning of frame +#define MCASP_DATA_FORMAT_VALUE 0x1807C // MSB first, 1 bit delay, 16 bits, CFG bus, ROR 16bits +#define MCASP_ACLKXCTL_VALUE 0x80 // Transmit on rising edge, sync. xmit and recv +#define MCASP_TDM_VALUE 0x03 // Enable TDM slots 0 and 1 +#endif + +#ifdef TLV320_MODE_DSP +#define MCASP_AFSCTL_VALUE 0x100 // 2-slot TDM I2S mode, rising edge means beginning of frame +#define MCASP_ACLKXCTL_VALUE 0x00 // Transmit on falling edge, sync. xmit and recv +#define MCASP_DATA_FORMAT_VALUE 0x807C // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits +#define MCASP_TDM_VALUE 0x03 // Enable TDM slots 0 and 1 +#endif + +#ifdef TLV320_MODE_TDM +#ifdef MCASP_SLOT_16BITS +#define MCASP_AFSCTL_VALUE 0x800 // 16-slot TDM, rising edge means beginning of frame +#define MCASP_DATA_FORMAT_VALUE 0x807C // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits +#endif + +#ifdef MCASP_SLOT_32BITS +#define MCASP_AFSCTL_VALUE 0x400 // 8-slot TDM, rising edge means beginning of frame +#define MCASP_DATA_FORMAT_VALUE 0x80F8 // MSB first, 0 bit delay, 32 bits, CFG bus, ROR 0bits +#endif + +// 20 and 24 bit slots not supported in 256-cycle TDM +// Hypothetically, for 20 bits, MCASP_DATA_FORMAT_VALUE = 0x809B +// Hypothetically, for 24 bits, MCASP_DATA_FORMAT_VALUE = 0x80BA + +#define MCASP_ACLKXCTL_VALUE 0x00 // Transmit on falling edge, sync. xmit and recv +#define MCASP_TDM_VALUE 0x03 // Enable TDM slots 0 and 1 +#endif #define C_MCASP_MEM C28 // Shared PRU mem @@ -901,18 +952,27 @@ SPI_INIT_DONE: MCASP_REG_WRITE MCASP_DLBCTL, 0x00 MCASP_REG_WRITE MCASP_DITCTL, 0x00 MCASP_REG_WRITE MCASP_RMASK, MCASP_DATA_MASK // 16 bit data receive - MCASP_REG_WRITE MCASP_RFMT, MCASP_DATA_FORMAT // Set data format - MCASP_REG_WRITE MCASP_AFSRCTL, 0x100 // I2S mode + MCASP_REG_WRITE MCASP_RFMT, MCASP_DATA_FORMAT_VALUE // Set data format + MCASP_REG_WRITE MCASP_AFSRCTL, MCASP_AFSCTL_VALUE MCASP_REG_WRITE MCASP_ACLKRCTL, 0x80 // Sample on rising edge MCASP_REG_WRITE MCASP_AHCLKRCTL, 0x8001 // Internal clock, not inv, /2; irrelevant? - MCASP_REG_WRITE MCASP_RTDM, 0x03 // Enable TDM slots 0 and 1 + + // Calculate which TDM slots to activate + LBBO r2, reg_comm_addr, COMM_ACTIVE_TDM_SLOTS, 4 // How many audio channels? + MOV r3, 0x1 // mask = (1 << numchannels) - 1 + LSL r3, r3, r2 + SUB r3, r3, 1 + OR r3, r3, 0x03 // Always activate the first two slots (failsafe) + AND r3, r3, 0x1F // Never more than 32 slots + + MCASP_REG_WRITE MCASP_RTDM, r3 // Set enabled TDM slots MCASP_REG_WRITE MCASP_RINTCTL, 0x00 // No interrupts MCASP_REG_WRITE MCASP_XMASK, MCASP_DATA_MASK // 16 bit data transmit - MCASP_REG_WRITE MCASP_XFMT, MCASP_DATA_FORMAT // Set data format - MCASP_REG_WRITE MCASP_AFSXCTL, 0x100 // I2S mode - MCASP_REG_WRITE MCASP_ACLKXCTL, 0x00 // Transmit on rising edge, sync. xmit and recv + MCASP_REG_WRITE MCASP_XFMT, MCASP_DATA_FORMAT_VALUE // Set data format + MCASP_REG_WRITE MCASP_AFSXCTL, MCASP_AFSCTL_VALUE + MCASP_REG_WRITE MCASP_ACLKXCTL, MCASP_ACLKXCTL_VALUE MCASP_REG_WRITE MCASP_AHCLKXCTL, 0x8001 // External clock from AHCLKX - MCASP_REG_WRITE MCASP_XTDM, 0x03 // Enable TDM slots 0 and 1 + MCASP_REG_WRITE MCASP_XTDM, r3 // Set enabled TDM slots MCASP_REG_WRITE MCASP_XINTCTL, 0x00 // No interrupts MCASP_REG_WRITE_EXT MCASP_SRCTL_R, 0x02 // Set up receive serialiser @@ -1008,6 +1068,11 @@ MCASP_ADC_WAIT_BEFORE_LOOP: QBBC MCASP_ADC_WAIT_BEFORE_LOOP, r2, MCASP_RSTAT_RDATA_BIT MCASP_REG_READ_EXT MCASP_RBUF, r2 + +// TODO: may need to wait a full cycle in TDM mode >2 channels; see XSLOT register +// ...but which slot do we wait for, and how do we know to skip inactive slots? +// LBBO r2, reg_mcasp_addr, MCASP_XSLOT, 4 +// QBNE MCASP_DAC_WAIT_BEFORE_LOOP, r2, 0 WRITE_ONE_BUFFER: @@ -1065,11 +1130,22 @@ MCASP_DAC_LOW_WORD: // Mask out the low word (first in little endian) MOV r2, 0xFFFF AND r7, reg_mcasp_dac_data, r2 + +#ifdef MCASP_SLOT_32BITS + LSL r7, r7, 16 // Convert 16-bit number to 32-bit +#endif QBA MCASP_WAIT_XSTAT MCASP_DAC_HIGH_WORD: // Take the high word of the previously loaded data - LSR r7, reg_mcasp_dac_data, 16 +#ifdef MCASP_SLOT_16BITS + LSR r7, reg_mcasp_dac_data, 16 // Move high word to low 16 bits +#endif + +#ifdef MCASP_SLOT_32BITS + MOV r2, 0xFFFF0000 + AND r7, reg_mcasp_dac_data, r2 // Mask out low 16 bits +#endif // Every 2 channels we send one audio sample; this loop already // sends exactly two SPI channels. @@ -1096,6 +1172,9 @@ MCASP_WAIT_RSTAT_LOW: // Mask low word and store in ADC data register MCASP_REG_READ_EXT MCASP_RBUF, r3 +#ifdef MCASP_SLOT_32BITS + LSR r3, r3, 16 // 32-bit value to 16-bit +#endif MOV r2, 0xFFFF AND reg_mcasp_adc_data, r3, r2 QBA MCASP_ADC_DONE @@ -1108,7 +1187,14 @@ MCASP_WAIT_RSTAT_HIGH: // Read data and shift 16 bits to the left (into the high word) MCASP_REG_READ_EXT MCASP_RBUF, r3 - LSL r3, r3, 16 +#ifdef MCASP_SLOT_16BITS + LSL r3, r3, 16 // 16-bit value to high part of word +#endif + +#ifdef MCASP_SLOT_32BITS + MOV r2, 0xFFFF0000 // Mask out low 16 bits of 32-bit word + AND r3, r3, r2 +#endif OR reg_mcasp_adc_data, reg_mcasp_adc_data, r3 // Now store the result and increment the pointer From 951cb0a97e5383e54749ebc75a9a8c0fbc91fb98 Mon Sep 17 00:00:00 2001 From: Andrew McPherson Date: Sun, 11 Aug 2019 00:06:19 +0100 Subject: [PATCH 002/148] First implementation of multiple codec support. PRU code needs to be changed depending on whether running in DSP or TDM mode. Works with 2 channels in either case, not with more channels. (cherry pick of commits 7101946d and 8468cfd0) --- Makefile | 2 +- core/I2c_Codec.cpp | 86 ++++++-------- core/I2c_MultiTLVCodec.cpp | 230 ++++++++++++++++++++++++++++++++++++ core/PRU.cpp | 15 ++- core/RTAudio.cpp | 28 ++++- core/board_detect.cpp | 22 +++- include/Bela.h | 1 + include/I2c_Codec.h | 6 +- include/I2c_MultiTLVCodec.h | 47 ++++++++ 9 files changed, 368 insertions(+), 69 deletions(-) create mode 100644 core/I2c_MultiTLVCodec.cpp create mode 100644 include/I2c_MultiTLVCodec.h diff --git a/Makefile b/Makefile index 96d8cc121..fc20f6609 100644 --- a/Makefile +++ b/Makefile @@ -392,7 +392,7 @@ ALL_DEPS += $(addprefix build/core/,$(notdir $(CORE_C_SRCS:.c=.d))) CORE_CPP_SRCS = $(filter-out core/default_main.cpp core/default_libpd_render.cpp, $(wildcard core/*.cpp)) CORE_OBJS := $(CORE_OBJS) $(addprefix build/core/,$(notdir $(CORE_CPP_SRCS:.cpp=.o))) -CORE_CORE_OBJS := build/core/RTAudio.o build/core/PRU.o build/core/RTAudioCommandLine.o build/core/I2c_Codec.o build/core/Spi_Codec.o build/core/math_runfast.o build/core/GPIOcontrol.o build/core/PruBinary.o build/core/board_detect.o build/core/DataFifo.o build/core/BelaContextFifo.o build/core/BelaContextSplitter.o build/core/MiscUtilities.o build/core/Mmap.o +CORE_CORE_OBJS := build/core/RTAudio.o build/core/PRU.o build/core/RTAudioCommandLine.o build/core/I2c_Codec.o build/core/I2c_MultiTLVCodec.o build/core/Spi_Codec.o build/core/math_runfast.o build/core/GPIOcontrol.o build/core/PruBinary.o build/core/board_detect.o build/core/DataFifo.o build/core/BelaContextFifo.o build/core/BelaContextSplitter.o build/core/MiscUtilities.o build/core/Mmap.o EXTRA_CORE_OBJS := $(filter-out $(CORE_CORE_OBJS), $(CORE_OBJS)) ALL_DEPS += $(addprefix build/core/,$(notdir $(CORE_CPP_SRCS:.cpp=.d))) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 291254540..f67ce6d04 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -15,11 +15,10 @@ #include "../include/I2c_Codec.h" #define TLV320_DSP_MODE -#define TLV320_256CLOCK_MODE I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, bool isVerbose /*= false*/) : dacVolumeHalfDbs(0), adcVolumeHalfDbs(0), hpVolumeHalfDbs(0), - slotSize(16), slotOffset(0), master(true), running(false) + master(true), running(false) { setVerbose(isVerbose); initI2C_RW(i2cBus, i2cAddress, -1); @@ -47,10 +46,10 @@ int I2c_Codec::initCodec() // it runs at 44.1kHz int I2c_Codec::startAudio(int dual_rate) { - return startAudio(dual_rate, 1); + return startAudio(dual_rate, 1, 0, 16, 0); } -int I2c_Codec::startAudio(int dual_rate, int is_master) +int I2c_Codec::startAudio(int dual_rate, int is_master, int tdm_mode, int slotSize, int startingSlot) { master = is_master; @@ -59,7 +58,7 @@ int I2c_Codec::startAudio(int dual_rate, int is_master) // Explicit Switch to config register page 0: if(writeRegister(0x00, 0x00)) // Page Select Register return 1; - + // see datasehet for TLV320AIC3104 from page 44 if(writeRegister(0x02, 0x00)) // Codec sample rate register: fs_ref / 1 return 1; @@ -105,38 +104,38 @@ int I2c_Codec::startAudio(int dual_rate, int is_master) return 1; } -#ifdef TLV320_256CLOCK_MODE // for multi-codec mode - unsigned int crb; // Audio serial control register B - if(slotSize == 16) - crb = 0x48; - else if(slotSize == 20) - crb = 0x58; - else if(slotSize == 24) - crb = 0x68; - else if(slotSize == 32) - crb = 0x78; - else - return 1; + if(tdm_mode) { + unsigned int crb; // Audio serial control register B + if(slotSize == 16) + crb = 0x48; + else if(slotSize == 20) + crb = 0x58; + else if(slotSize == 24) + crb = 0x68; + else if(slotSize == 32) + crb = 0x78; + else + return 1; - if(writeRegister(0x09, crb)) // Audio serial control register B: DSP mode, word len specified by slotSize - return 1; - if(writeRegister(0x0A, slotOffset*slotSize)) // Audio serial control register C: offset of 16 bits per slot - return 1; -#else + if(writeRegister(0x09, crb)) // Audio serial control register B: DSP mode, word len specified by slotSize + return 1; + if(writeRegister(0x0A, startingSlot*slotSize)) // Audio serial control register C: specifying offset in bits + return 1; + } + else { #ifdef TLV320_DSP_MODE // to use with old PRU code - if(writeRegister(0x09, 0x40)) // Audio serial control register B: DSP mode, word len 16 bits + if(writeRegister(0x09, 0x40)) // Audio serial control register B: DSP mode, word len 16 bits #else - if(writeRegister(0x09, 0x00)) // Audio serial control register B: I2S mode, word len 16 bits + if(writeRegister(0x09, 0x00)) // Audio serial control register B: I2S mode, word len 16 bits #endif - return 1; + return 1; #ifdef TLV320_DSP_MODE // to use with old PRU code - if(writeRegister(0x0A, 0x00)) // Audio serial control register C: 0 bit offset + if(writeRegister(0x0A, 0x00)) // Audio serial control register C: 0 bit offset #else - if(writeRegister(0x0A, 0x01)) // Audio serial control register C: 1 bit offset + if(writeRegister(0x0A, 0x01)) // Audio serial control register C: 1 bit offset #endif - return 1; -#endif // TLV320_256CLOCK_MODE - + return 1; + } if(writeRegister(0x0D, 0x00)) // Headset / button press register A: disabled return 1; if(writeRegister(0x0E, 0x00)) // Headset / button press register B: disabled @@ -163,7 +162,7 @@ int I2c_Codec::startAudio(int dual_rate, int is_master) if(writeRegister(0x66, 0x82)) // Clock generation control register: use BCLK, PLL N = 2 return 1; } - + //Set-up hardware high-pass filter for DC removal if(configureDCRemovalIIR()) return 1; @@ -171,10 +170,12 @@ int I2c_Codec::startAudio(int dual_rate, int is_master) return 1; // TODO: may need to separate the code below for non-master codecs so they enable amps after the master clock starts - + // wait for the codec to stabilize before unmuting the HP amp. // this gets rid of the loud pop. - usleep(10000); + if(is_master) + usleep(10000); + // note : a small click persists, but it is unavoidable // (i.e.: fading in the hpVolumeHalfDbs after it is turned on does not remove it). @@ -283,25 +284,6 @@ int I2c_Codec::configureDCRemovalIIR(){ return 0; } - -// Set the size of the I2S/DSP/TDM slots in bits -int I2c_Codec::setSlotSize(unsigned int size) { - if(size != 16 && size != 20 && size != 24 && size != 32) - return 1; - - slotSize = size; - return 0; -} - -// Set the slot in an 8-cycle TDM format where the first channel should be read (slot ranges from 0 to 7) -int I2c_Codec::setFirstTDMSlot(unsigned int slot) { - if(slot > 7) - return 1; - - slotOffset = slot; - return 0; -} - //set the numerator multiplier for the PLL int I2c_Codec::setPllK(float k){ short unsigned int j=(int)k; diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp new file mode 100644 index 000000000..1f26d27cc --- /dev/null +++ b/core/I2c_MultiTLVCodec.cpp @@ -0,0 +1,230 @@ +/* + * I2c_MultiTLVCodec.h + * + * Wrapper for multiple copies of the TLV320AIC310x + * codec on the same McASP TDM bus (but with different + * I2C addresses). Codec 0 provides the clock signals + * via its PLL and the other codecs are clocked to it. + * + * Created on: August 9, 2019 + * Author: Andrew McPherson + */ + +#include +#include "../include/I2c_MultiTLVCodec.h" + +I2c_MultiTLVCodec::I2c_MultiTLVCodec(int i2cBus, int i2cAddress, bool isVerbose /*= false*/) +: masterCodec(0), running(false), verbose(isVerbose) +{ + for(int address = i2cAddress; address < i2cAddress + 4; address++) { + // Check for presence of TLV codec and take the first one we find as the master codec + I2c_Codec *testCodec = new I2c_Codec(i2cBus, address); + if(testCodec->initCodec() != 0) { + delete testCodec; + } + else { + // codec found + if(verbose) { + fprintf(stderr, "Found I2C codec on bus %d address %d\n", i2cBus, address); + } + + if(!masterCodec) + masterCodec = testCodec; + else + extraCodecs.push_back(testCodec); + } + } +} + +// This method initialises the audio codec to its default state +int I2c_MultiTLVCodec::initCodec() +{ + int ret = 0; + if(!masterCodec) + return 1; + if((ret = masterCodec->initCodec())) + return ret; + + std::vector::iterator it; + for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + if((ret = (*it)->initCodec())) + return ret; + } + + return 0; +} + +// Tell the codec to start generating audio +int I2c_MultiTLVCodec::startAudio(int dual_rate) +{ + // Supported values of slot size in the PRU code: 16 and 32 bits. Note that + // altering slot size requires changing #defines in the PRU code. + const int slotSize = 16; + int slotNum = 0; + int ret = 0; + + if(!masterCodec) + return 1; + + // Master codec generates the clocks with its PLL and occupies the first two slots + if((ret = masterCodec->startAudio(dual_rate, 1, 1, slotSize, 0))) + return ret; + + // Each subsequent codec occupies the next 2 slots + std::vector::iterator it; + for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + slotNum += 2; + if((ret = (*it)->startAudio(dual_rate, 0, 1, slotSize, slotNum))) + return ret; + } + + running = true; + return 0; +} + + +int I2c_MultiTLVCodec::stopAudio() +{ + int ret = 0; + if(!masterCodec) + return 1; + + if(running) { + // Stop extra codecs + std::vector::iterator it; + for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + (*it)->stopAudio(); + } + + // Stop master codec providing the clock; return value from this codec + ret = masterCodec->stopAudio(); + } + + running = false; + return ret; +} + +int I2c_MultiTLVCodec::setPga(float newGain, unsigned short int channel) +{ + int ret = 0; + if(!masterCodec) + return 1; + + if((ret = masterCodec->setPga(newGain, channel))) + return ret; + + std::vector::iterator it; + for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + if((ret = (*it)->setPga(newGain, channel))) + return ret; + } + + return 0; +} + +int I2c_MultiTLVCodec::setDACVolume(int halfDbSteps) +{ + int ret = 0; + if(!masterCodec) + return 1; + + if((ret = masterCodec->setDACVolume(halfDbSteps))) + return ret; + + std::vector::iterator it; + for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + if((ret = (*it)->setDACVolume(halfDbSteps))) + return ret; + } + + return 0; +} + +int I2c_MultiTLVCodec::setADCVolume(int halfDbSteps) +{ + int ret = 0; + if(!masterCodec) + return 1; + + if((ret = masterCodec->setADCVolume(halfDbSteps))) + return ret; + + std::vector::iterator it; + for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + if((ret = (*it)->setADCVolume(halfDbSteps))) + return ret; + } + + return 0; +} + +int I2c_MultiTLVCodec::setHPVolume(int halfDbSteps) +{ + int ret = 0; + if(!masterCodec) + return 1; + + if((ret = masterCodec->setHPVolume(halfDbSteps))) + return ret; + + std::vector::iterator it; + for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + if((ret = (*it)->setHPVolume(halfDbSteps))) + return ret; + } + + return 0; +} + +int I2c_MultiTLVCodec::disable() +{ + if(!masterCodec) + return 1; + + // Disable extra codecs first + std::vector::iterator it; + for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + (*it)->stopAudio(); + } + + // Disable master codec providing the clock; return value from this codec + return masterCodec->stopAudio(); +} + +int I2c_MultiTLVCodec::reset() +{ + int ret = 0; + if(!masterCodec) + return 1; + + if((ret = masterCodec->reset())) + return ret; + + std::vector::iterator it; + for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + if((ret = (*it)->reset())) + return ret; + } + + return 0; +} + +// How many I2C codecs were found? (range 0-4) +int I2c_MultiTLVCodec::numDetectedCodecs() +{ + if(!masterCodec) + return 0; + return extraCodecs.size() + 1; +} + +I2c_MultiTLVCodec::~I2c_MultiTLVCodec() +{ + stopAudio(); + + // Delete codec objects we created + std::vector::iterator it; + for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) + delete *it; + if(masterCodec) + delete masterCodec; +} diff --git a/core/PRU.cpp b/core/PRU.cpp index eab67ca24..3ddafaf0a 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -309,7 +309,7 @@ int PRU::prepareGPIO(int include_led) } if(context->digitalFrames != 0){ - if(belaHw == BelaHw_BelaMini) + if(belaHw == BelaHw_BelaMini || belaHw == BelaHw_BelaMiniMultiAudio) { gDigitalPins = digitalPinsPocketBeagle; } else { @@ -334,7 +334,7 @@ int PRU::prepareGPIO(int include_led) } if(include_led) { - if(belaHw == BelaHw_BelaMini) + if(belaHw == BelaHw_BelaMini || belaHw == BelaHw_BelaMiniMultiAudio) { //using on-board LED gpio_export(belaMiniLedBlue); @@ -377,7 +377,7 @@ void PRU::cleanupGPIO() } } if(led_enabled) { - if(belaHw == BelaHw_BelaMini) + if(belaHw == BelaHw_BelaMini || belaHw == BelaHw_BelaMiniMultiAudio) { //using on-board LED gpio_unexport(belaMiniLedBlue); @@ -421,7 +421,7 @@ int PRU::initialise(BelaHw newBelaHw, int pru_num, bool uniformSampleRate, int m if(0 <= stopButtonPin){ stopButton.open(stopButtonPin, Gpio::INPUT, false); } - if(belaHw == BelaHw_BelaMini && enableLed){ + if((belaHw == BelaHw_BelaMini || belaHw == BelaHw_BelaMiniMultiAudio) && enableLed){ underrunLed.open(belaMiniLedRed, Gpio::OUTPUT); underrunLed.clear(); } @@ -589,6 +589,7 @@ void PRU::initialisePruCommon() uint32_t board_flags = 0; switch(belaHw) { case BelaHw_BelaMini: + case BelaHw_BelaMiniMultiAudio: board_flags |= 1 << BOARD_FLAGS_BELA_MINI; break; case BelaHw_CtagFace: @@ -623,7 +624,7 @@ void PRU::initialisePruCommon() pru_buffer_comm[PRU_SYNC_PIN_MASK] = 0; pru_buffer_comm[PRU_PRU_NUMBER] = pru_number; pru_buffer_comm[PRU_ERROR_OCCURRED] = 0; - pru_buffer_comm[PRU_ACTIVE_TDM_SLOTS] = 2; // Default value; TODO: make this adjustable + pru_buffer_comm[PRU_ACTIVE_TDM_SLOTS] = context->audioOutChannels; /* Set up multiplexer info */ if(context->multiplexerChannels == 2) { @@ -642,7 +643,7 @@ void PRU::initialisePruCommon() } if(led_enabled) { - if(belaHw == BelaHw_BelaMini) + if(belaHw == BelaHw_BelaMini || belaHw == BelaHw_BelaMiniMultiAudio) { pru_buffer_comm[PRU_LED_ADDRESS] = belaMiniLedBlueGpioBase; pru_buffer_comm[PRU_LED_PIN_MASK] = belaMiniLedBlueGpioPinMask; @@ -682,6 +683,8 @@ int PRU::start(char * const filename) //nobreak case BelaHw_BelaMini: //nobreak + case BelaHw_BelaMiniMultiAudio: + //nobreak case BelaHw_Salt: pruUsesMcaspIrq = false; break; diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index c6f67375e..f2f46c53b 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -52,6 +52,7 @@ #include "../include/PRU.h" #include "../include/I2c_Codec.h" #include "../include/Spi_Codec.h" +#include "../include/I2c_MultiTLVCodec.h" #include "../include/GPIOcontrol.h" extern "C" void enable_runfast(); extern "C" void disable_runfast(); @@ -121,6 +122,7 @@ typedef struct static I2c_Codec* gI2cCodec = NULL; static Spi_Codec* gSpiCodec = NULL; int gRTAudioVerbose = 0; // Verbosity level for debugging +static I2c_MultiTLVCodec* gI2cMultiTLVCodec = NULL; AudioCodec* gAudioCodec = NULL; static int Bela_getHwConfigPrivate(BelaHw hw, BelaHwConfig* cfg, BelaHwConfigPrivate* pcfg) @@ -143,6 +145,10 @@ static int Bela_getHwConfigPrivate(BelaHw hw, BelaHwConfig* cfg, BelaHwConfigPri activeCodec = gI2cCodec; disabledCodec = gSpiCodec; break; + case BelaHw_BelaMiniMultiAudio: + cfg->activeCodec = gI2cMultiTLVCodec; + cfg->disabledCodec = gSpiCodec; + break; case BelaHw_CtagFace: //nobreak case BelaHw_CtagFaceBela: @@ -173,6 +179,23 @@ static int Bela_getHwConfigPrivate(BelaHw hw, BelaHwConfig* cfg, BelaHwConfigPri cfg->audioOutChannels = 2; cfg->audioSampleRate = 44100; break; + case BelaHw_BelaMiniMultiAudio: + if(gI2cMultiTLVCodec) { + if(gI2cMultiTLVCodec->numDetectedCodecs() > 0) { + cfg->audioInChannels = 2*gI2cMultiTLVCodec->numDetectedCodecs(); + cfg->audioOutChannels = 2*gI2cMultiTLVCodec->numDetectedCodecs(); + } + else { + cfg->audioInChannels = 2; + cfg->audioOutChannels = 2; + } + } + else { + cfg->audioInChannels = 2; + cfg->audioOutChannels = 2; + } + cfg->audioSampleRate = 44100; + break; case BelaHw_CtagFace: //nobreak case BelaHw_CtagFaceBela: @@ -468,8 +491,11 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) gSpiCodec = new Spi_Codec(ctagSpidevGpioCs0, NULL); else if(belaHw == BelaHw_CtagBeast || belaHw == BelaHw_CtagBeastBela) gSpiCodec = new Spi_Codec(ctagSpidevGpioCs0, ctagSpidevGpioCs1); - if(belaHw != BelaHw_CtagBeast && belaHw != BelaHw_CtagFace) + if(belaHw != BelaHw_CtagBeast && belaHw != BelaHw_CtagFace && belaHw != BelaHw_BelaMiniMultiAudio) gI2cCodec = new I2c_Codec(codecI2cBus, codecI2cAddress, gRTAudioVerbose); + if(belaHw == BelaHw_BelaMiniMultiAudio) + gI2cMultiTLVCodec = new I2c_MultiTLVCodec(codecI2cBus, codecI2cAddress, gRTAudioVerbose); + BelaHwConfig cfg; BelaHwConfigPrivate pcfg; if(Bela_getHwConfigPrivate(belaHw, &cfg, &pcfg)) diff --git a/core/board_detect.cpp b/core/board_detect.cpp index 76c6014e1..7da0b8dd4 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -62,9 +62,9 @@ static std::string trim(std::string const& str) // Returns true if the Tlv32 codec is detected // Returns false if the Tlv32 codec is not detected -static bool detectTlv32() +static bool detectTlv32(int bus, int address) { - I2c_Codec codec(codecI2cBus, codecI2cAddress); + I2c_Codec codec(bus, address); // I2c_Codec codec(i2cBus, i2cAddress); // get these variable from RTAudio.cpp int ret = codec.initCodec(); if (ret == 0) @@ -114,6 +114,8 @@ BelaHw getBelaHw(std::string board) hw = BelaHw_CtagFaceBela; else if(board == "CtagBeastBela") hw = BelaHw_CtagBeastBela; + else if(board == "BelaMiniMultiAudio") + hw = BelaHw_BelaMiniMultiAudio; else hw = BelaHw_NoHw; return hw; @@ -145,6 +147,9 @@ std::string getBelaHwName(BelaHw hardware) case BelaHw_CtagBeastBela: hwName = "CtagBeastBela"; break; + case BelaHw_BelaMiniMultiAudio: + hwName = "BelaMiniMultiAudio"; + break; default: hwName = ""; break; @@ -202,12 +207,21 @@ BelaHw Bela_detectHw() return hw; if(is_belamini()) { - hw = BelaHw_BelaMini; + bool hasTlv32[4]; + + for(int i = 0; i < 4; i++) + hasTlv32[i] = detectTlv32(codecI2cBus, codecI2cAddress + i); + + if(hasTlv32[1] || hasTlv32[2] || hasTlv32[3]) + hw = BelaHw_BelaMiniMultiAudio; + else if(hasTlv32[0]) + hw = BelaHw_BelaMini; } else { int ctag = detectCtag(); - bool hasTlv32 = detectTlv32(); + bool hasTlv32 = detectTlv32(codecI2cBus, codecI2cAddress); + if(ctag == 1) { if(hasTlv32) diff --git a/include/Bela.h b/include/Bela.h index 9f898f8fa..68ab7f19f 100644 --- a/include/Bela.h +++ b/include/Bela.h @@ -86,6 +86,7 @@ typedef enum BelaHw_CtagBeast, BelaHw_CtagFaceBela, BelaHw_CtagBeastBela, + BelaHw_BelaMiniMultiAudio } BelaHw; typedef struct _BelaHwConfig diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index a3562bfc2..bab6b85d2 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -31,11 +31,9 @@ class I2c_Codec : public I2c, public AudioCodec int initCodec(); int startAudio(int dual_rate); - int startAudio(int dual_rate, int is_master); + int startAudio(int dual_rate, int is_master, int tdm_mode, int slotSize, int startingSlot); int stopAudio(); - int setSlotSize(unsigned int size); - int setFirstTDMSlot(unsigned int slot); int setPllJ(short unsigned int j); int setPllD(unsigned int d); int setPllP(short unsigned int p); @@ -71,8 +69,6 @@ class I2c_Codec : public I2c, public AudioCodec int dacVolumeHalfDbs; int adcVolumeHalfDbs; int hpVolumeHalfDbs; - int slotSize; - int slotOffset; bool master; bool running; bool verbose; diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h new file mode 100644 index 000000000..cb0a14410 --- /dev/null +++ b/include/I2c_MultiTLVCodec.h @@ -0,0 +1,47 @@ +/* + * I2c_MultiTLVCodec.h + * + * Wrapper for multiple copies of the TLV320AIC310x + * codec on the same McASP TDM bus (but with different + * I2C addresses). Codec 0 provides the clock signals + * via its PLL and the other codecs are clocked to it. + * + * Created on: August 9, 2019 + * Author: Andrew McPherson + */ + + +#ifndef I2C_MULTITLV_CODEC_H_ +#define I2C_MULTITLV_CODEC_H_ + +#include "I2c_Codec.h" + +class I2c_MultiTLVCodec : public AudioCodec +{ +public: + int initCodec(); + int startAudio(int dual_rate); + int stopAudio(); + + int setPga(float newGain, unsigned short int channel); + int setDACVolume(int halfDbSteps); + int setADCVolume(int halfDbSteps); + int setHPVolume(int halfDbSteps); + int disable(); + int reset(); + + int numDetectedCodecs(); + + I2c_MultiTLVCodec(int i2cBus, int i2cAddress, bool verbose = false); + ~I2c_MultiTLVCodec(); + +private: + I2c_Codec *masterCodec; + std::vector extraCodecs; + + bool running; + bool verbose; +}; + + +#endif /* I2C_MULTITLV_CODEC_H_ */ From b5c6f477ce9f679485d45dcfa1ed260092c15e2e Mon Sep 17 00:00:00 2001 From: Andrew McPherson Date: Mon, 21 Oct 2019 22:26:34 +0100 Subject: [PATCH 003/148] Move the multi-TLV codec to the IRQ PRU code. Probably not working at this stage. (cherry picked from commit c2a0a40bfa96f258430b9d16612a771201a2acd5, with an edit (removing commented out lines in core/board_detect.cpp) --- core/I2c_MultiTLVCodec.cpp | 1 + core/PRU.cpp | 8 +- core/RTAudio.cpp | 5 +- core/board_detect.cpp | 4 +- include/Bela.h | 2 +- include/I2c_MultiTLVCodec.h | 9 +- include/PruArmCommon.h | 1 + pru/pru_rtaudio_irq.p | 292 ++++++++++++++++++++++++++++++++++-- 8 files changed, 298 insertions(+), 24 deletions(-) diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 1f26d27cc..c0171a45c 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -16,6 +16,7 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(int i2cBus, int i2cAddress, bool isVerbose /*= false*/) : masterCodec(0), running(false), verbose(isVerbose) { + // for(int address = i2cAddress + 3; address >= i2cAddress; address--) { for(int address = i2cAddress; address < i2cAddress + 4; address++) { // Check for presence of TLV codec and take the first one we find as the master codec I2c_Codec *testCodec = new I2c_Codec(i2cBus, address); diff --git a/core/PRU.cpp b/core/PRU.cpp index 3ddafaf0a..c851ae83d 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -589,9 +589,11 @@ void PRU::initialisePruCommon() uint32_t board_flags = 0; switch(belaHw) { case BelaHw_BelaMini: - case BelaHw_BelaMiniMultiAudio: board_flags |= 1 << BOARD_FLAGS_BELA_MINI; break; + case BelaHw_BelaMiniMultiAudio: + board_flags |= 1 << BOARD_FLAGS_BELA_MULTI_TLV; + break; case BelaHw_CtagFace: case BelaHw_CtagFaceBela: board_flags |= 1 << BOARD_FLAGS_CTAG_FACE; @@ -683,11 +685,11 @@ int PRU::start(char * const filename) //nobreak case BelaHw_BelaMini: //nobreak - case BelaHw_BelaMiniMultiAudio: - //nobreak case BelaHw_Salt: pruUsesMcaspIrq = false; break; + case BelaHw_BelaMiniMultiAudio: + //nobreak case BelaHw_CtagFace: //nobreak case BelaHw_CtagBeast: diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index f2f46c53b..8c74b5104 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -227,6 +227,7 @@ static int Bela_getHwConfigPrivate(BelaHw hw, BelaHwConfig* cfg, BelaHwConfigPri cfg->analogInChannels = 8; cfg->analogOutChannels = 8; break; + case BelaHw_BelaMiniMultiAudio: case BelaHw_BelaMini: cfg->analogInChannels = 8; break; @@ -469,7 +470,9 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) // Initialise the rendering environment: sample rates, frame counts, numbers of channels BelaHw belaHw = Bela_detectHw(); - if(gRTAudioVerbose) + // belaHw = BelaHw_BelaMini; + // belaHw = BelaHw_BelaMiniMultiAudio; // TESTING + if(gRTAudioVerbose) printf("Detected hardware: %s\n", getBelaHwName(belaHw).c_str()); // Check for user-selected hardware BelaHw userHw = settings->board; diff --git a/core/board_detect.cpp b/core/board_detect.cpp index 7da0b8dd4..78a8f8b1e 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -209,8 +209,10 @@ BelaHw Bela_detectHw() { bool hasTlv32[4]; - for(int i = 0; i < 4; i++) + for(int i = 0; i < 4; i++) { hasTlv32[i] = detectTlv32(codecI2cBus, codecI2cAddress + i); + printf("codec at %d = %d\n", codecI2cAddress + i, hasTlv32[i]); + } if(hasTlv32[1] || hasTlv32[2] || hasTlv32[3]) hw = BelaHw_BelaMiniMultiAudio; diff --git a/include/Bela.h b/include/Bela.h index 68ab7f19f..5534ddb77 100644 --- a/include/Bela.h +++ b/include/Bela.h @@ -86,7 +86,7 @@ typedef enum BelaHw_CtagBeast, BelaHw_CtagFaceBela, BelaHw_CtagBeastBela, - BelaHw_BelaMiniMultiAudio + BelaHw_BelaMiniMultiAudio, } BelaHw; typedef struct _BelaHwConfig diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index cb0a14410..82afa52d1 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -10,9 +10,7 @@ * Author: Andrew McPherson */ - -#ifndef I2C_MULTITLV_CODEC_H_ -#define I2C_MULTITLV_CODEC_H_ +#pragma once #include "I2c_Codec.h" @@ -41,7 +39,4 @@ class I2c_MultiTLVCodec : public AudioCodec bool running; bool verbose; -}; - - -#endif /* I2C_MULTITLV_CODEC_H_ */ +}; \ No newline at end of file diff --git a/include/PruArmCommon.h b/include/PruArmCommon.h index 269ef8bb2..d980313b1 100644 --- a/include/PruArmCommon.h +++ b/include/PruArmCommon.h @@ -5,6 +5,7 @@ #define BOARD_FLAGS_BELA_MINI 0 #define BOARD_FLAGS_CTAG_FACE 1 #define BOARD_FLAGS_CTAG_BEAST 2 +#define BOARD_FLAGS_BELA_MULTI_TLV 3 #define PRU_SYSTEM_EVENT_RTDM 20 #define PRU_SYS_EV_MCASP_RX_INTR 54 // mcasp_r_intr_pend diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index bfc7daa2e..1c3ac4427 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -11,15 +11,16 @@ // At least one needs to be selected. Maximum 2 can be selected without having // the "jump too long" error mentioned above -#define ENABLE_CTAG_FACE // enables run-time selection of the CTAG Face codec. -#define ENABLE_CTAG_BEAST // enables run-time selection of the CTAG Beast codecs -//#define ENABLE_BELA_TLV32 // enables run-time selection of the Bela TLV32 codec +//#define ENABLE_CTAG_FACE // enables run-time selection of the CTAG Face codec. +//#define ENABLE_CTAG_BEAST // enables run-time selection of the CTAG Beast codecs +#define ENABLE_BELA_TLV32 // enables run-time selection of the Bela TLV32 codec +//#define ENABLE_BELA_MULTI_TLV32 // enables run-time selection of multiple Bela TLV32 codecs //#define ENABLE_MUXER // enables run-time selection of the Multiplexer capelet // there are some issues with this code and this codec. // See https://github.com/BelaPlatform/Bela/issues/480 #define CTAG_IGNORE_UNUSED_INPUT_TDM_SLOTS -#define MCASP_INPUTS_ARE_HALF_AS_MANY_AS_OUTPUTS // TODO: make it runtime (should not be there for BELA_TLV) +//#define MCASP_INPUTS_ARE_HALF_AS_MANY_AS_OUTPUTS // TODO: make it runtime (should not be there for BELA_TLV) #define DBOX_CAPE // Define this to use new cape hardware @@ -136,6 +137,7 @@ #define COMM_BUFFER_SPI_FRAMES 60 // How many frames per buffer for analog i/o #define COMM_BOARD_FLAGS 64 // Flags for the board we are on (BOARD_FLAGS_... are defined in include/PruBoardFlags.h) #define COMM_ERROR_OCCURED 68 // Signals the ARM CPU that an error happened +#define COMM_ACTIVE_TDM_SLOTS 72 // How many TDM slots contain useful data #define ARM_ERROR_TIMEOUT 1 #define ARM_ERROR_XUNDRUN 2 @@ -350,19 +352,33 @@ #define CTAG_BEAST_MCASP_RINTCTL_VALUE MCASP_RINTCTL_VALUE #define CTAG_BEAST_MCASP_XINTCTL_VALUE MCASP_XINTCTL_VALUE -#define BELA_TLV_MCASP_DATA_FORMAT_TX_VALUE 0x18074 // MSB first, 1 bit delay, 16 bits, DAT bus, ROR 16bits -#define BELA_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x28074 // MSB first, 2 bit delay, 16 bits, DAT bus, ROR 16bits +#define BELA_TLV_MCASP_DATA_FORMAT_TX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits +#define BELA_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits #define BELA_TLV_MCASP_ACLKRCTL_VALUE 0x00 // External clk, polarity (falling edge) #define BELA_TLV_MCASP_ACLKXCTL_VALUE 0x00 // External clk, polarity (falling edge) #define BELA_TLV_MCASP_AHCLKRCTL_VALUE MCASP_AHCLKRCTL_VALUE #define BELA_TLV_MCASP_AHCLKXCTL_VALUE MCASP_AHCLKXCTL_VALUE #define BELA_TLV_MCASP_AFSRCTL_VALUE 0x100 // 2 Slot I2S, external clk, polarity (rising edge), single bit -#define BELA_TLV_MCASP_AFSXCTL_VALUE 0x101 // 2 Slot I2S, external clk, polarity (falling edge), single bit +#define BELA_TLV_MCASP_AFSXCTL_VALUE 0x100 // 2 Slot I2S, external clk, polarity (rising edge), single bit #define BELA_TLV_MCASP_RTDM_VALUE 0x3 // Enable TDM slots 0 and 1 #define BELA_TLV_MCASP_XTDM_VALUE 0x3 // Enable TDM slots 0 and 1 #define BELA_TLV_MCASP_RINTCTL_VALUE MCASP_RINTCTL_VALUE #define BELA_TLV_MCASP_XINTCTL_VALUE MCASP_XINTCTL_VALUE +// Values below are for 16x 16-bit TDM slots + +#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits +#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits +#define BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE 0x00 // External clk, polarity (falling edge) +#define BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE 0x00 // External clk, polarity (falling edge) +#define BELA_MULTI_TLV_MCASP_AHCLKRCTL_VALUE MCASP_AHCLKRCTL_VALUE +#define BELA_MULTI_TLV_MCASP_AHCLKXCTL_VALUE MCASP_AHCLKXCTL_VALUE +#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x800 // 16-slot TDM, rising edge means beginning of frame +#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x800 // 16-slot TDM, rising edge means beginning of frame +// RTDM and XTDM are calculated dynamically +#define BELA_MULTI_TLV_MCASP_RINTCTL_VALUE MCASP_RINTCTL_VALUE +#define BELA_MULTI_TLV_MCASP_XINTCTL_VALUE MCASP_XINTCTL_VALUE + #define C_MCASP_MEM C28 // Shared PRU mem // Flags for the flags register @@ -382,6 +398,12 @@ #define FLAG_BIT_CTAG 11 #define FLAG_BIT_CTAG_FACE 12 #define FLAG_BIT_CTAG_BEAST 13 +#define FLAG_BIT_BELA_MULTI_TLV 14 + +#define FLAG_BIT_AUDIO_CHANNELS0 16 +#define FLAG_BIT_AUDIO_CHANNELS1 17 +#define FLAG_BIT_AUDIO_CHANNELS2 18 +#define FLAG_BIT_AUDIO_CHANNELS3 19 // Registers used throughout @@ -450,6 +472,16 @@ MOV r31.b0, PRU_SYSTEM_EVENT_RTDM_WRITE_VALUE QBBC DEST, reg_flags, FLAG_BIT_BELA_MINI .endm +.macro BELA_MULTI_TLV_OR_JMP_TO +.mparam DEST + QBBC DEST, reg_flags, FLAG_BIT_BELA_MULTI_TLV +.endm + +.macro BELA_NOT_MULTI_TLV_OR_JMP_TO +.mparam DEST + QBBS DEST, reg_flags, FLAG_BIT_BELA_MULTI_TLV +.endm + .macro CTAG_OR_JMP_TO .mparam DEST QBBC DEST, reg_flags, FLAG_BIT_CTAG @@ -517,6 +549,16 @@ SETINPUT: //if it is an input, set the relevant bit DONE: .endm +// Read the number of audio channels from the flags register +// 4 bits indicate pairs of channels (i.e. 2 to 32) +.macro READ_MULTI_TLV_CHANNELS +.mparam DEST + LSR DEST, reg_flags, FLAG_BIT_AUDIO_CHANNELS0 + AND DEST, DEST, 0x0F + ADD DEST, DEST, 1 + LSL DEST, DEST, 1 +.endm + QBA START // when first starting, go to START, skipping this section. DIGITAL: @@ -1016,6 +1058,10 @@ PRU_NUMBER_CHECK_DONE: QBBC BELA_MINI_CHECK_DONE, r2, BOARD_FLAGS_BELA_MINI SET reg_flags, reg_flags, FLAG_BIT_BELA_MINI BELA_MINI_CHECK_DONE: + // Find out whether we are on a multi-TLV Bela setup + QBBC BELA_MULTI_TLV_CHECK_DONE, r2, BOARD_FLAGS_BELA_MULTI_TLV + SET reg_flags, reg_flags, FLAG_BIT_BELA_MULTI_TLV +BELA_MULTI_TLV_CHECK_DONE: // Find out whether we are on CTAG_FACE QBBC CTAG_FACE_CHECK_DONE, r2, BOARD_FLAGS_CTAG_FACE SET reg_flags, reg_flags, FLAG_BIT_CTAG_FACE @@ -1186,8 +1232,37 @@ MCASP_SET_RX_NOT_CTAG_FACE: MCASP_SET_RX_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ #ifdef ENABLE_BELA_TLV32 + BELA_NOT_MULTI_TLV_OR_JMP_TO MCASP_SET_RX_MULTI_TLV MCASP_SET_RX BELA_TLV_MCASP_DATA_FORMAT_RX_VALUE, BELA_TLV_MCASP_AFSRCTL_VALUE, BELA_TLV_MCASP_ACLKRCTL_VALUE, BELA_TLV_MCASP_AHCLKRCTL_VALUE, BELA_TLV_MCASP_RTDM_VALUE, BELA_TLV_MCASP_RINTCTL_VALUE, MCASP_DATA_MASK +MCASP_SET_RX_MULTI_TLV: #endif /* ENABLE_BELA_TLV32 */ +#ifdef ENABLE_BELA_MULTI_TLV32 + BELA_MULTI_TLV_OR_JMP_TO MCASP_SET_RX_NOT_MULTI_TLV + + // reg_flags should hold the number of active channels, up to + // 32, in pairs (i.e. 0 --> 2, 1 --> 4, ..., 15 --> 32) + LBBO r2, reg_comm_addr, COMM_ACTIVE_TDM_SLOTS, 4 // How many audio channels? + + QBNE MCASP_SET_RX_MULTI_TLV_NONZERO, r2, 0 + LDI r2, 2 // Sanity check: empty value defaults to stereo +MCASP_SET_RX_MULTI_TLV_NONZERO: + LSR r3, r2, 1 + SUB r3, r3, 1 // r3 = (r3 / 2) - 1 + AND r3, r3, 0x0F // mask out high bits (sanity check) + LSL r3, r3, FLAG_BIT_AUDIO_CHANNELS0 // shift to the right bit offset + OR reg_flags, reg_flags, r3 // this works because we know these bits are 0 in reg_flags before now + + // Calculate which TDM slots to activate + MOV r3, 0x1 // mask = (1 << numchannels) - 1 + LSL r3, r3, r2 + SUB r3, r3, 1 + OR r3, r3, 0x03 // Always activate the first two slots (failsafe) + AND r3, r3, 0x1F // Never more than 32 slots + + MCASP_SET_RX BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE, BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE, BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE, BELA_MULTI_TLV_MCASP_AHCLKRCTL_VALUE, r3, BELA_MULTI_TLV_MCASP_RINTCTL_VALUE, MCASP_DATA_MASK +MCASP_SET_RX_NOT_MULTI_TLV: +#endif /* ENABLE_BELA_MULTI_TLV32 */ + MCASP_SET_RX_DONE: // set MCASP TX @@ -1204,8 +1279,24 @@ MCASP_SET_TX_NOT_CTAG_FACE: MCASP_SET_TX_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ #ifdef ENABLE_BELA_TLV32 + BELA_NOT_MULTI_TLV_OR_JMP_TO MCASP_SET_TX_MULTI_TLV MCASP_SET_TX BELA_TLV_MCASP_DATA_FORMAT_TX_VALUE, BELA_TLV_MCASP_AFSXCTL_VALUE, BELA_TLV_MCASP_ACLKXCTL_VALUE, BELA_TLV_MCASP_AHCLKXCTL_VALUE, BELA_TLV_MCASP_XTDM_VALUE, BELA_TLV_MCASP_XINTCTL_VALUE +MCASP_SET_TX_MULTI_TLV: #endif /* ENABLE_BELA_TLV32 */ +#ifdef ENABLE_BELA_MULTI_TLV32 + BELA_MULTI_TLV_OR_JMP_TO MCASP_SET_TX_NOT_MULTI_TLV + + // Calculate which TDM slots to activate + LBBO r2, reg_comm_addr, COMM_ACTIVE_TDM_SLOTS, 4 // How many audio channels? + MOV r3, 0x1 // mask = (1 << numchannels) - 1 + LSL r3, r3, r2 + SUB r3, r3, 1 + OR r3, r3, 0x03 // Always activate the first two slots (failsafe) + AND r3, r3, 0x1F // Never more than 32 slots + + MCASP_SET_TX BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE, BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE, BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE, BELA_MULTI_TLV_MCASP_AHCLKXCTL_VALUE, r3, BELA_MULTI_TLV_MCASP_XINTCTL_VALUE +MCASP_SET_TX_NOT_MULTI_TLV: +#endif /* ENABLE_BELA_MULTI_TLV32 */ MCASP_SET_TX_DONE: MCASP_REG_WRITE_EXT MCASP_SRCTL_R, 0x02 // Set up receive serialiser @@ -1276,9 +1367,22 @@ WRITE_FRAME_NOT_CTAG_FACE: WRITE_FRAME_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ #ifdef ENABLE_BELA_TLV32 + BELA_NOT_MULTI_TLV_OR_JMP_TO WRITE_FRAME_MULTI_TLV MCASP_WRITE_TO_DATAPORT 0x00, 4 MCASP_WRITE_TO_DATAPORT 0x00, 4 +WRITE_FRAME_MULTI_TLV: #endif /* ENABLE_BELA_TLV32 */ +#ifdef ENABLE_BELA_MULTI_TLV32 + BELA_MULTI_TLV_OR_JMP_TO WRITE_FRAME_NOT_MULTI_TLV + + READ_MULTI_TLV_CHANNELS r2 // How many channels? +WRITE_FRAME_MULTI_TLV_LOOP: + MCASP_WRITE_TO_DATAPORT 0x00, 4 // Write 4 bytes for each channel + SUB r2, r2, 1 + QBGT WRITE_FRAME_MULTI_TLV_LOOP, r2, 0 + +WRITE_FRAME_NOT_MULTI_TLV: +#endif /* ENABLE_BELA_MULTI_TLV32 */ WRITE_FRAME_DONE: MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 4) // Set RFRST @@ -1432,7 +1536,7 @@ INNER_EVENT_LOOP: // Check if ARM says should finish: flag is zero as long as it should run LBBO r27, reg_comm_addr, COMM_SHOULD_STOP, 4 - QBNE CLEANUP, r27, 0 + QBNE GO_TO_CLEANUP, r27, 0 SUB r28, r28, 1 QBNE MCASP_CHECK_TX_ERROR_END, r28, 0 @@ -1440,6 +1544,11 @@ INNER_EVENT_LOOP: // an interrupt, an error must have occurred SEND_ERROR_TO_ARM ARM_ERROR_TIMEOUT JMP START // TODO: should HALT and wait for ARM to restart + +GO_TO_CLEANUP: + JMP CLEANUP + + MCASP_CHECK_TX_ERROR_END: QBBC INNER_EVENT_LOOP, r31, PRU_INTR_BIT_CH1 @@ -1533,21 +1642,42 @@ CTAG_BEAST_OR_JMP_TO LOAD_AUDIO_FRAME_NOT_CTAG_BEAST LOAD_AUDIO_FRAME_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ #ifdef ENABLE_BELA_TLV32 +BELA_NOT_MULTI_TLV_OR_JMP_TO LOAD_AUDIO_FRAME_MULTI_TLV LBCO r0, C_MCASP_MEM, reg_mcasp_dac_current, 4 SBCO r8, C_MCASP_MEM, reg_mcasp_dac_current, 4 ADD reg_mcasp_dac_current, reg_mcasp_dac_current, 4 +LOAD_AUDIO_FRAME_MULTI_TLV: #endif /* ENABLE_BELA_TLV32 */ +#ifdef ENABLE_BELA_MULTI_TLV32 +BELA_MULTI_TLV_OR_JMP_TO LOAD_AUDIO_FRAME_NOT_MULTI_TLV + // Number of bytes to load depends on number of active TDM slots + // LBCO/SBCO only support r0 as indicator of number of bytes + // so load begins from r1 + LDI r16, 0 + + // TLVTODO: this only works up to 16 channels based on number of registers + READ_MULTI_TLV_CHANNELS r0 + QBLT LOAD_AUDIO_FRAME_MULTI_TLV_LT16CHAN, r0, 16 + LDI r0, 16 +LOAD_AUDIO_FRAME_MULTI_TLV_LT16CHAN: + LSL r0, r0, 1 // 16 bits per channel + LBCO r1, C_MCASP_MEM, reg_mcasp_dac_current, b0 + SBCO r9, C_MCASP_MEM, reg_mcasp_dac_current, b0 + ADD reg_mcasp_dac_current, reg_mcasp_dac_current, r0.b0 + +LOAD_AUDIO_FRAME_NOT_MULTI_TLV: +#endif /* ENABLE_BELA_MULTI_TLV32 */ LOAD_AUDIO_FRAME_DONE: //TODO: Change data structure in RAM to 32 bit samples // => no masking and shifting required // => support for 24 bit audio MOV r17, 0xFFFF - AND r8, r17, r0 - LSR r9, r0, 16 #ifdef ENABLE_CTAG_FACE CTAG_FACE_OR_JMP_TO WRITE_AUDIO_FRAME_NOT_CTAG_FACE + AND r8, r17, r0 + LSR r9, r0, 16 AND r10, r17, r1 LSR r11, r1, 16 AND r12, r17, r2 @@ -1562,6 +1692,8 @@ WRITE_AUDIO_FRAME_NOT_CTAG_FACE: CTAG_BEAST_OR_JMP_TO WRITE_AUDIO_FRAME_NOT_CTAG_BEAST // Note: Could be optimized by only using single operation to write data to McASP FIFO, // but 24 registers need to be free for use + AND r8, r17, r0 + LSR r9, r0, 16 AND r10, r17, r1 LSR r11, r1, 16 AND r12, r17, r2 @@ -1583,8 +1715,60 @@ CTAG_BEAST_OR_JMP_TO WRITE_AUDIO_FRAME_NOT_CTAG_BEAST WRITE_AUDIO_FRAME_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ #ifdef ENABLE_BELA_TLV32 +BELA_NOT_MULTI_TLV_OR_JMP_TO WRITE_AUDIO_FRAME_MULTI_TLV + AND r8, r17, r0 + LSR r9, r0, 16 + + LDI r8, 0 + LDI r9, 0xFFFF MCASP_WRITE_TO_DATAPORT r8, 8 +WRITE_AUDIO_FRAME_MULTI_TLV: #endif /* ENABLE_BELA_TLV32 */ +#ifdef ENABLE_BELA_MULTI_TLV32 +BELA_MULTI_TLV_OR_JMP_TO WRITE_AUDIO_FRAME_NOT_MULTI_TLV + AND r9, r17, r1 + LSR r10, r1, 16 + MCASP_WRITE_TO_DATAPORT r9, 8 + QBLE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 4 // r0 = channels * 2 + + AND r11, r17, r2 + LSR r12, r2, 16 + MCASP_WRITE_TO_DATAPORT r11, 8 + QBLE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 8 + + AND r13, r17, r3 + LSR r14, r3, 16 + MCASP_WRITE_TO_DATAPORT r13, 8 + QBLE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 12 + + AND r15, r17, r4 + LSR r16, r4, 16 + MCASP_WRITE_TO_DATAPORT r15, 8 + QBLE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 16 + + AND r9, r17, r5 + LSR r10, r5, 16 + MCASP_WRITE_TO_DATAPORT r9, 8 + QBLE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 20 + + AND r11, r17, r6 + LSR r12, r6, 16 + MCASP_WRITE_TO_DATAPORT r11, 8 + QBLE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 24 + + AND r13, r17, r7 + LSR r14, r7, 16 + MCASP_WRITE_TO_DATAPORT r13, 8 + QBLE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 28 + + AND r15, r17, r8 + LSR r16, r8, 16 + MCASP_WRITE_TO_DATAPORT r15, 8 + // (r0 * 2) >= 32 + +WRITE_AUDIO_FRAME_MULTI_TLV_DONE: +WRITE_AUDIO_FRAME_NOT_MULTI_TLV: +#endif /* ENABLE_BELA_MULTI_TLV32 */ WRITE_AUDIO_FRAME_DONE: XIN SCRATCHPAD_ID_BANK0, r0, 72 // load back register states from scratchpad @@ -1695,6 +1879,7 @@ SKIP_AUDIO_RX_FRAME: FRAME_READ_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ #ifdef ENABLE_BELA_TLV32 + BELA_NOT_MULTI_TLV_OR_JMP_TO FRAME_READ_MULTI_TLV MCASP_READ_FROM_DATAPORT r8, 32 AND r0, r8, r17 @@ -1703,7 +1888,71 @@ FRAME_READ_NOT_CTAG_BEAST: SBCO r0, C_MCASP_MEM, reg_mcasp_adc_current, 4 // store result ADD reg_mcasp_adc_current, reg_mcasp_adc_current, 4 // increment memory pointer +FRAME_READ_MULTI_TLV: #endif /* ENABLE_BELA_TLV32 */ +#ifdef ENABLE_BELA_MULTI_TLV32 + BELA_MULTI_TLV_OR_JMP_TO FRAME_READ_NOT_MULTI_TLV + + READ_MULTI_TLV_CHANNELS r0 + QBLT FRAME_READ_MULTI_TLV_LT16CHAN, r0, 16 + LDI r0, 16 +FRAME_READ_MULTI_TLV_LT16CHAN: + LSL r0, r0, 1 // 16 bits per channel + + MCASP_READ_FROM_DATAPORT r9, 8 // TLVTODO: should this be 32 bytes like above? + AND r1, r9, r17 + LSL r10, r10, 16 + OR r1, r1, r10 + QBLE FRAME_READ_MULTI_TLV_STORE, r0, 4 // r0 = channels * 2 + + MCASP_READ_FROM_DATAPORT r9, 8 + AND r2, r9, r17 + LSL r10, r10, 16 + OR r2, r2, r10 + QBLE FRAME_READ_MULTI_TLV_STORE, r0, 8 + + MCASP_READ_FROM_DATAPORT r9, 8 + AND r3, r9, r17 + LSL r10, r10, 16 + OR r3, r3, r10 + QBLE FRAME_READ_MULTI_TLV_STORE, r0, 12 + + MCASP_READ_FROM_DATAPORT r9, 8 + AND r4, r9, r17 + LSL r10, r10, 16 + OR r4, r4, r10 + QBLE FRAME_READ_MULTI_TLV_STORE, r0, 16 + + MCASP_READ_FROM_DATAPORT r9, 8 + AND r5, r9, r17 + LSL r10, r10, 16 + OR r5, r5, r10 + QBLE FRAME_READ_MULTI_TLV_STORE, r0, 20 + + MCASP_READ_FROM_DATAPORT r9, 8 + AND r6, r9, r17 + LSL r10, r10, 16 + OR r6, r6, r10 + QBLE FRAME_READ_MULTI_TLV_STORE, r0, 24 + + MCASP_READ_FROM_DATAPORT r9, 8 + AND r7, r9, r17 + LSL r10, r10, 16 + OR r7, r7, r10 + QBLE FRAME_READ_MULTI_TLV_STORE, r0, 28 + + MCASP_READ_FROM_DATAPORT r9, 8 + AND r8, r9, r17 + LSL r10, r10, 16 + OR r8, r8, r10 + +FRAME_READ_MULTI_TLV_STORE: + SBCO r1, C_MCASP_MEM, reg_mcasp_adc_current, b0 // store result + ADD reg_mcasp_adc_current, reg_mcasp_adc_current, r0.b0 // increment memory pointer + +FRAME_READ_NOT_MULTI_TLV: +#endif /* ENABLE_BELA_MULTI_TLV32 */ + FRAME_READ_DONE: XIN SCRATCHPAD_ID_BANK0, r0, 72 // load back register states from scratchpad @@ -1972,6 +2221,7 @@ CTAG_BEAST_16CH_ANALOG_CFG_END: SET_REG_FRAMES_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ #ifdef ENABLE_BELA_TLV32 +BELA_NOT_MULTI_TLV_OR_JMP_TO BELA_TLV_ANALOG_CFG_END // Set reg frames total based on number of analog channels // 8 analog ch => LSL 1 // 4 analog ch => no shifting @@ -1987,6 +2237,25 @@ BELA_TLV_ANALOG_2: // Two channels LSR r14, reg_frame_mcasp_total, 1 BELA_TLV_ANALOG_CFG_END: #endif /* ENABLE_BELA_TLV32 */ +#ifdef ENABLE_BELA_MULTI_TLV32 +BELA_MULTI_TLV_OR_JMP_TO BELA_MULTI_TLV_ANALOG_CFG_END + // Set reg frames total based on number of analog channels + // 8 analog ch => LSL 1 + // 4 analog ch => no shifting + // 2 analog ch => LSR 1 + QBEQ BELA_MULTI_TLV_ANALOG_8, reg_num_channels, 0x8 + QBEQ BELA_MULTI_TLV_ANALOG_CFG_END, reg_num_channels, 0x4 + QBEQ BELA_MULTI_TLV_ANALOG_8, reg_num_channels, 0x2 + +BELA_MULTI_TLV_ANALOG_8: // Eight channels + LSL r14, reg_frame_spi_total, 1 + JMP BELA_MULTI_TLV_ANALOG_CFG_END +BELA_MULTI_TLV_ANALOG_2: // Two channels + LSR r14, reg_frame_spi_total, 1 + +BELA_MULTI_TLV_ANALOG_CFG_END: +#endif /* ENABLE_BELA_MULTI_TLV32 */ + SET_REG_FRAMES_DONE: ADD reg_frame_current, reg_frame_current, 1 @@ -2044,7 +2313,8 @@ LED_BLINK_OFF: LED_BLINK_DONE: // Check if we should finish: flag is zero as long as it should run LBBO r2, reg_comm_addr, COMM_SHOULD_STOP, 4 - QBEQ WRITE_ONE_BUFFER, r2, 0 + QBNE CLEANUP, r2, 0 + JMP WRITE_ONE_BUFFER CLEANUP: MCASP_REG_WRITE MCASP_GBLCTL, 0x00 // Turn off McASP From fc5adbbc9ce410acd564d093d6c0e626938104ad Mon Sep 17 00:00:00 2001 From: Andrew McPherson Date: Fri, 25 Oct 2019 22:48:23 +0100 Subject: [PATCH 004/148] Multichannel audio output now mostly works, but channels are in the wrong order and one of them is noise. Input is not working yet. (cherry picked from commit c85656fc9cf8a454df8313cd641a5676c6c1b945) --- pru/pru_rtaudio_irq.p | 83 +++++++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 22 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 1c3ac4427..40ecce162 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -14,7 +14,7 @@ //#define ENABLE_CTAG_FACE // enables run-time selection of the CTAG Face codec. //#define ENABLE_CTAG_BEAST // enables run-time selection of the CTAG Beast codecs #define ENABLE_BELA_TLV32 // enables run-time selection of the Bela TLV32 codec -//#define ENABLE_BELA_MULTI_TLV32 // enables run-time selection of multiple Bela TLV32 codecs +#define ENABLE_BELA_MULTI_TLV32 // enables run-time selection of multiple Bela TLV32 codecs //#define ENABLE_MUXER // enables run-time selection of the Multiplexer capelet // there are some issues with this code and this codec. // See https://github.com/BelaPlatform/Bela/issues/480 @@ -1258,7 +1258,7 @@ MCASP_SET_RX_MULTI_TLV_NONZERO: SUB r3, r3, 1 OR r3, r3, 0x03 // Always activate the first two slots (failsafe) AND r3, r3, 0x1F // Never more than 32 slots - + MCASP_SET_RX BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE, BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE, BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE, BELA_MULTI_TLV_MCASP_AHCLKRCTL_VALUE, r3, BELA_MULTI_TLV_MCASP_RINTCTL_VALUE, MCASP_DATA_MASK MCASP_SET_RX_NOT_MULTI_TLV: #endif /* ENABLE_BELA_MULTI_TLV32 */ @@ -1293,7 +1293,7 @@ MCASP_SET_TX_MULTI_TLV: SUB r3, r3, 1 OR r3, r3, 0x03 // Always activate the first two slots (failsafe) AND r3, r3, 0x1F // Never more than 32 slots - + MCASP_SET_TX BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE, BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE, BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE, BELA_MULTI_TLV_MCASP_AHCLKXCTL_VALUE, r3, BELA_MULTI_TLV_MCASP_XINTCTL_VALUE MCASP_SET_TX_NOT_MULTI_TLV: #endif /* ENABLE_BELA_MULTI_TLV32 */ @@ -1375,11 +1375,17 @@ WRITE_FRAME_MULTI_TLV: #ifdef ENABLE_BELA_MULTI_TLV32 BELA_MULTI_TLV_OR_JMP_TO WRITE_FRAME_NOT_MULTI_TLV + + // TLVTODO TESTNG + //MCASP_WRITE_TO_DATAPORT 0x00, 4 + //MCASP_WRITE_TO_DATAPORT 0x00, 4 + //QBA WRITE_FRAME_NOT_MULTI_TLV + READ_MULTI_TLV_CHANNELS r2 // How many channels? WRITE_FRAME_MULTI_TLV_LOOP: MCASP_WRITE_TO_DATAPORT 0x00, 4 // Write 4 bytes for each channel SUB r2, r2, 1 - QBGT WRITE_FRAME_MULTI_TLV_LOOP, r2, 0 + QBNE WRITE_FRAME_MULTI_TLV_LOOP, r2, 0 WRITE_FRAME_NOT_MULTI_TLV: #endif /* ENABLE_BELA_MULTI_TLV32 */ @@ -1650,6 +1656,13 @@ LOAD_AUDIO_FRAME_MULTI_TLV: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 BELA_MULTI_TLV_OR_JMP_TO LOAD_AUDIO_FRAME_NOT_MULTI_TLV + + // TLVTODO TESTING + //LBCO r0, C_MCASP_MEM, reg_mcasp_dac_current, 4 + //SBCO r8, C_MCASP_MEM, reg_mcasp_dac_current, 4 + //ADD reg_mcasp_dac_current, reg_mcasp_dac_current, 4 + //QBA LOAD_AUDIO_FRAME_NOT_MULTI_TLV + // Number of bytes to load depends on number of active TDM slots // LBCO/SBCO only support r0 as indicator of number of bytes // so load begins from r1 @@ -1657,13 +1670,16 @@ BELA_MULTI_TLV_OR_JMP_TO LOAD_AUDIO_FRAME_NOT_MULTI_TLV // TLVTODO: this only works up to 16 channels based on number of registers READ_MULTI_TLV_CHANNELS r0 - QBLT LOAD_AUDIO_FRAME_MULTI_TLV_LT16CHAN, r0, 16 + QBGT LOAD_AUDIO_FRAME_MULTI_TLV_LT16CHAN, r0, 16 LDI r0, 16 LOAD_AUDIO_FRAME_MULTI_TLV_LT16CHAN: LSL r0, r0, 1 // 16 bits per channel LBCO r1, C_MCASP_MEM, reg_mcasp_dac_current, b0 SBCO r9, C_MCASP_MEM, reg_mcasp_dac_current, b0 ADD reg_mcasp_dac_current, reg_mcasp_dac_current, r0.b0 + +// MOV r0, r1 // TLVTODO TESTING +// MOV r8, r9 LOAD_AUDIO_FRAME_NOT_MULTI_TLV: #endif /* ENABLE_BELA_MULTI_TLV32 */ @@ -1719,47 +1735,56 @@ BELA_NOT_MULTI_TLV_OR_JMP_TO WRITE_AUDIO_FRAME_MULTI_TLV AND r8, r17, r0 LSR r9, r0, 16 - LDI r8, 0 - LDI r9, 0xFFFF MCASP_WRITE_TO_DATAPORT r8, 8 WRITE_AUDIO_FRAME_MULTI_TLV: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 BELA_MULTI_TLV_OR_JMP_TO WRITE_AUDIO_FRAME_NOT_MULTI_TLV + + + // TLVTODO TESTING + //AND r8, r17, r0 + //LSR r9, r0, 16 + + //LDI r8, 0 + //LDI r9, 0xFFFF + //MCASP_WRITE_TO_DATAPORT r8, 8 + //QBA WRITE_AUDIO_FRAME_NOT_MULTI_TLV + AND r9, r17, r1 LSR r10, r1, 16 MCASP_WRITE_TO_DATAPORT r9, 8 - QBLE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 4 // r0 = channels * 2 + QBGE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 4 // r0 = channels * 2 AND r11, r17, r2 LSR r12, r2, 16 MCASP_WRITE_TO_DATAPORT r11, 8 - QBLE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 8 + QBGE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 8 AND r13, r17, r3 LSR r14, r3, 16 MCASP_WRITE_TO_DATAPORT r13, 8 - QBLE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 12 + QBGE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 12 AND r15, r17, r4 LSR r16, r4, 16 MCASP_WRITE_TO_DATAPORT r15, 8 - QBLE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 16 + QBGE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 16 AND r9, r17, r5 LSR r10, r5, 16 MCASP_WRITE_TO_DATAPORT r9, 8 - QBLE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 20 + QBGE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 20 AND r11, r17, r6 LSR r12, r6, 16 MCASP_WRITE_TO_DATAPORT r11, 8 - QBLE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 24 + QBGE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 24 AND r13, r17, r7 LSR r14, r7, 16 MCASP_WRITE_TO_DATAPORT r13, 8 - QBLE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 28 + QBGE WRITE_AUDIO_FRAME_MULTI_TLV_DONE, r0, 28 AND r15, r17, r8 LSR r16, r8, 16 @@ -1893,8 +1918,22 @@ FRAME_READ_MULTI_TLV: #ifdef ENABLE_BELA_MULTI_TLV32 BELA_MULTI_TLV_OR_JMP_TO FRAME_READ_NOT_MULTI_TLV + // TLVTODO TESTING + + //MCASP_READ_FROM_DATAPORT r8, 32 + //AND r0, r8, r17 + //LSL r16, r9, 16 + //OR r0, r0, r16 + + //SBCO r0, C_MCASP_MEM, reg_mcasp_adc_current, 4 // store result + //ADD reg_mcasp_adc_current, reg_mcasp_adc_current, 4 // increment memory pointer + + //QBA FRAME_READ_NOT_MULTI_TLV + + // END TLVTODO TESTING + READ_MULTI_TLV_CHANNELS r0 - QBLT FRAME_READ_MULTI_TLV_LT16CHAN, r0, 16 + QBGT FRAME_READ_MULTI_TLV_LT16CHAN, r0, 16 LDI r0, 16 FRAME_READ_MULTI_TLV_LT16CHAN: LSL r0, r0, 1 // 16 bits per channel @@ -1903,43 +1942,43 @@ FRAME_READ_MULTI_TLV_LT16CHAN: AND r1, r9, r17 LSL r10, r10, 16 OR r1, r1, r10 - QBLE FRAME_READ_MULTI_TLV_STORE, r0, 4 // r0 = channels * 2 + QBGE FRAME_READ_MULTI_TLV_STORE, r0, 4 // r0 = channels * 2 MCASP_READ_FROM_DATAPORT r9, 8 AND r2, r9, r17 LSL r10, r10, 16 OR r2, r2, r10 - QBLE FRAME_READ_MULTI_TLV_STORE, r0, 8 + QBGE FRAME_READ_MULTI_TLV_STORE, r0, 8 MCASP_READ_FROM_DATAPORT r9, 8 AND r3, r9, r17 LSL r10, r10, 16 OR r3, r3, r10 - QBLE FRAME_READ_MULTI_TLV_STORE, r0, 12 + QBGE FRAME_READ_MULTI_TLV_STORE, r0, 12 MCASP_READ_FROM_DATAPORT r9, 8 AND r4, r9, r17 LSL r10, r10, 16 OR r4, r4, r10 - QBLE FRAME_READ_MULTI_TLV_STORE, r0, 16 + QBGE FRAME_READ_MULTI_TLV_STORE, r0, 16 MCASP_READ_FROM_DATAPORT r9, 8 AND r5, r9, r17 LSL r10, r10, 16 OR r5, r5, r10 - QBLE FRAME_READ_MULTI_TLV_STORE, r0, 20 + QBGE FRAME_READ_MULTI_TLV_STORE, r0, 20 MCASP_READ_FROM_DATAPORT r9, 8 AND r6, r9, r17 LSL r10, r10, 16 OR r6, r6, r10 - QBLE FRAME_READ_MULTI_TLV_STORE, r0, 24 + QBGE FRAME_READ_MULTI_TLV_STORE, r0, 24 MCASP_READ_FROM_DATAPORT r9, 8 AND r7, r9, r17 LSL r10, r10, 16 OR r7, r7, r10 - QBLE FRAME_READ_MULTI_TLV_STORE, r0, 28 + QBGE FRAME_READ_MULTI_TLV_STORE, r0, 28 MCASP_READ_FROM_DATAPORT r9, 8 AND r8, r9, r17 From e39376e6cb95956c264c6d8b60ef3cbe3cc20331 Mon Sep 17 00:00:00 2001 From: Andrew McPherson Date: Sun, 27 Oct 2019 15:25:14 +0000 Subject: [PATCH 005/148] Fixed erroneous TDM slot configuration. Multichannel TLV output now appears to work. (cherry picked from commit 2998ded21ed39f65f57aa005c070eb13ededff45) --- pru/pru_rtaudio_irq.p | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 40ecce162..53bedb33a 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -1257,8 +1257,7 @@ MCASP_SET_RX_MULTI_TLV_NONZERO: LSL r3, r3, r2 SUB r3, r3, 1 OR r3, r3, 0x03 // Always activate the first two slots (failsafe) - AND r3, r3, 0x1F // Never more than 32 slots - + MCASP_SET_RX BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE, BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE, BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE, BELA_MULTI_TLV_MCASP_AHCLKRCTL_VALUE, r3, BELA_MULTI_TLV_MCASP_RINTCTL_VALUE, MCASP_DATA_MASK MCASP_SET_RX_NOT_MULTI_TLV: #endif /* ENABLE_BELA_MULTI_TLV32 */ @@ -1292,8 +1291,7 @@ MCASP_SET_TX_MULTI_TLV: LSL r3, r3, r2 SUB r3, r3, 1 OR r3, r3, 0x03 // Always activate the first two slots (failsafe) - AND r3, r3, 0x1F // Never more than 32 slots - + MCASP_SET_TX BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE, BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE, BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE, BELA_MULTI_TLV_MCASP_AHCLKXCTL_VALUE, r3, BELA_MULTI_TLV_MCASP_XINTCTL_VALUE MCASP_SET_TX_NOT_MULTI_TLV: #endif /* ENABLE_BELA_MULTI_TLV32 */ From 247a187b7766a4a919783d375bb84f264cfc4a6a Mon Sep 17 00:00:00 2001 From: Andrew McPherson Date: Tue, 12 Nov 2019 18:00:12 +0000 Subject: [PATCH 006/148] Adapted registers for TLV320AIC3106 codec, which differ for the line inputs. Audio input now appears to work for multichannel. May also address an issue with spurious levels on the WCLK line. (cherry picked from commit 5d36b099ae19abdb68ee3152e8663e91365a44bc) --- core/I2c_Codec.cpp | 42 +++++++++++++++++++++++--------------- core/I2c_MultiTLVCodec.cpp | 4 +++- core/PRU.cpp | 7 +++++-- core/RTAudio.cpp | 2 +- core/board_detect.cpp | 2 +- include/I2c_Codec.h | 8 +++++++- 6 files changed, 43 insertions(+), 22 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index f67ce6d04..105bcd45d 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -16,8 +16,8 @@ #define TLV320_DSP_MODE -I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, bool isVerbose /*= false*/) -: dacVolumeHalfDbs(0), adcVolumeHalfDbs(0), hpVolumeHalfDbs(0), +I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, CodecType type, bool isVerbose /*= false*/) +: codecType(type), dacVolumeHalfDbs(0), adcVolumeHalfDbs(0), hpVolumeHalfDbs(0), master(true), running(false) { setVerbose(isVerbose); @@ -96,12 +96,12 @@ int I2c_Codec::startAudio(int dual_rate, int is_master, int tdm_mode, int slotSi } if(is_master) { - if(writeRegister(0x08, 0xC0)) // Audio serial control register A: BLCK, WCLK outputs - return 1; + if(writeRegister(0x08, 0xE0)) // Audio serial control register A: BLCK, WCLK outputs, + return 1; // DOUT tri-state when inactive } else { - if(writeRegister(0x08, 0x00)) // Audio serial control register A: BLCK, WCLK inputs - return 1; + if(writeRegister(0x08, 0x20)) // Audio serial control register A: BLCK, WCLK inputs, + return 1; // DOUT tri-state when inactive } if(tdm_mode) { @@ -163,7 +163,7 @@ int I2c_Codec::startAudio(int dual_rate, int is_master, int tdm_mode, int slotSi return 1; } - //Set-up hardware high-pass filter for DC removal + //Set-up hardware high-pass filter for DC removal -- TLVTODO: disable if(configureDCRemovalIIR()) return 1; if(writeRegister(25, 0b10000000)) // Enable mic bias 2.5V @@ -232,7 +232,7 @@ int I2c_Codec::configureDCRemovalIIR(){ // // Config Page 0 commands // - if(writeRegister(0x0C, 0x50)) // Digital filter register: enable HPF on L&R Channels + if(writeRegister(0x0C, 0x50)) // Digital filter register: enable HPF on L&R Channels -- TLVTODO: 0x00 for disabled return 1; if(writeRegister(0x6B, 0xC0)) // HPF coeff select register: Use programmable coeffs return 1; @@ -241,7 +241,7 @@ int I2c_Codec::configureDCRemovalIIR(){ if(writeRegister(0x00, 0x01)) //Page 1/Register 0: Page Select Register return 1; // - // Config Page 0 commands + // Config Page 1 commands // //Left Channel HPF Coeffiecient Registers @@ -488,10 +488,20 @@ int I2c_Codec::writeADCVolumeRegisters(bool mute) return 1; if(writeRegister(0x16, 0x7C)) // Line1R disabled; right ADC powered up with soft step return 1; - if(writeRegister(0x11, (volumeBits << 4) | 0x0F)) // Line2L connected to left ADC - return 1; - if(writeRegister(0x12, volumeBits | 0xF0)) // Line2R connected to right ADC - return 1; + + if(codecType == TLV320AIC3106) { + // Configure inputs as fully differential, weak biasing + if(writeRegister(0x14, (volumeBits << 3) | 0x84)) // Line2L connected to left ADC + return 1; + if(writeRegister(0x17, (volumeBits << 3) | 0x84)) // Line2R connected to right ADC + return 1; + } + else { // TLV320AIC3104 + if(writeRegister(0x11, (volumeBits << 4) | 0x0F)) // Line2L connected to left ADC + return 1; + if(writeRegister(0x12, volumeBits | 0xF0)) // Line2R connected to right ADC + return 1; + } } return 0; @@ -578,8 +588,8 @@ int I2c_Codec::stopAudio() return 1; if(writeRegister(0x03, 0x11)) // PLL register A: disable return 1; - if(writeRegister(0x01, 0x80)) // Reset codec to defaults - return 1; + //if(writeRegister(0x01, 0x80)) // Reset codec to defaults + // return 1; running = false; return 0; @@ -610,7 +620,7 @@ int I2c_Codec::disable(){ return 1; } else { - if (writeRegister(0x08, 0x00)) // Leave codec in slave mode + if (writeRegister(0x08, 0x20)) // Leave codec in slave mode return 1; } if(writeRegister(0x03, 0x11)) // PLL register A: disable diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index c0171a45c..5250c116a 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -19,7 +19,9 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(int i2cBus, int i2cAddress, bool isVerbose // for(int address = i2cAddress + 3; address >= i2cAddress; address--) { for(int address = i2cAddress; address < i2cAddress + 4; address++) { // Check for presence of TLV codec and take the first one we find as the master codec - I2c_Codec *testCodec = new I2c_Codec(i2cBus, address); + // TODO: this code assumes the first codec is a 3104 (Bela Mini cape), which might not always be true + I2c_Codec::CodecType type = (address == i2cAddress) ? I2c_Codec::TLV320AIC3104 : I2c_Codec::TLV320AIC3106; + I2c_Codec *testCodec = new I2c_Codec(i2cBus, address, type); if(testCodec->initCodec() != 0) { delete testCodec; } diff --git a/core/PRU.cpp b/core/PRU.cpp index c851ae83d..4cf9245a9 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -855,9 +855,12 @@ int PRU::testPruError() verbose && rt_fprintf(stderr, "Unknown PRU error: %d\n", errorCode); ret = 1; } + codec->stopAudio(); codec->reset(); - codec->initCodec(); - codec->startAudio(0); + //codec->initCodec(); + if(codec->startAudio(0)) { + rt_fprintf(stderr, "Error restarting codec\n"); + } pru_buffer_comm[PRU_ERROR_OCCURRED] = 0; // TODO: should restart PRU and codec from scratch return ret; diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 8c74b5104..5feacfd47 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -495,7 +495,7 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) else if(belaHw == BelaHw_CtagBeast || belaHw == BelaHw_CtagBeastBela) gSpiCodec = new Spi_Codec(ctagSpidevGpioCs0, ctagSpidevGpioCs1); if(belaHw != BelaHw_CtagBeast && belaHw != BelaHw_CtagFace && belaHw != BelaHw_BelaMiniMultiAudio) - gI2cCodec = new I2c_Codec(codecI2cBus, codecI2cAddress, gRTAudioVerbose); + gI2cCodec = new I2c_Codec(codecI2cBus, codecI2cAddress, I2c_Codec::TLV320AIC3104, gRTAudioVerbose); if(belaHw == BelaHw_BelaMiniMultiAudio) gI2cMultiTLVCodec = new I2c_MultiTLVCodec(codecI2cBus, codecI2cAddress, gRTAudioVerbose); diff --git a/core/board_detect.cpp b/core/board_detect.cpp index 78a8f8b1e..42a47fc9f 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -64,7 +64,7 @@ static std::string trim(std::string const& str) // Returns false if the Tlv32 codec is not detected static bool detectTlv32(int bus, int address) { - I2c_Codec codec(bus, address); + I2c_Codec codec(bus, address, I2c_Codec::TLV320AIC3104); // I2c_Codec codec(i2cBus, i2cAddress); // get these variable from RTAudio.cpp int ret = codec.initCodec(); if (ret == 0) diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index bab6b85d2..212722d0f 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -27,6 +27,11 @@ class I2c_Codec : public I2c, public AudioCodec short unsigned int pllP; short unsigned int pllR; public: + typedef enum { + TLV320AIC3104 = 0, + TLV320AIC3106, + } CodecType; + int writeRegister(unsigned int reg, unsigned int value); int initCodec(); @@ -61,11 +66,12 @@ class I2c_Codec : public I2c, public AudioCodec int readI2C(); void setVerbose(bool isVerbose); - I2c_Codec(int i2cBus, int I2cAddress, bool verbose = false); + I2c_Codec(int i2cBus, int I2cAddress, CodecType type, bool verbose = false); ~I2c_Codec(); private: int configureDCRemovalIIR(); //called by startAudio() + int codecType; int dacVolumeHalfDbs; int adcVolumeHalfDbs; int hpVolumeHalfDbs; From f4e75e192d9aa8d1d87f0150614f27af39e2a316 Mon Sep 17 00:00:00 2001 From: Andrew McPherson Date: Tue, 12 Nov 2019 18:14:53 +0000 Subject: [PATCH 007/148] Disable DC blocking for TLV320AIC3106 differential analog inputs (cherry picked from commit 2b09584e01c9b88e7467ed111f2e251d81ff61b4) --- core/I2c_Codec.cpp | 23 ++++++++++++++++++----- include/I2c_Codec.h | 2 +- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 105bcd45d..70c63bf41 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -162,10 +162,17 @@ int I2c_Codec::startAudio(int dual_rate, int is_master, int tdm_mode, int slotSi if(writeRegister(0x66, 0x82)) // Clock generation control register: use BCLK, PLL N = 2 return 1; } - - //Set-up hardware high-pass filter for DC removal -- TLVTODO: disable - if(configureDCRemovalIIR()) - return 1; + + //Set-up hardware high-pass filter for DC removal + if(codecType == TLV320AIC3104) { + if(configureDCRemovalIIR(true)) + return 1; + } + else { + // Disable DC blocking for differential analog inputs + if(configureDCRemovalIIR(false)) + return 1; + } if(writeRegister(25, 0b10000000)) // Enable mic bias 2.5V return 1; @@ -223,12 +230,18 @@ int I2c_Codec::startAudio(int dual_rate, int is_master, int tdm_mode, int slotSi // The selected cut-off should be acceptable up to 96 kHz sampling rate. // -int I2c_Codec::configureDCRemovalIIR(){ +int I2c_Codec::configureDCRemovalIIR(bool enable){ //Explicit Switch to config register page 0: if(writeRegister(0x00, 0x00)) //Page 1/Register 0: Page Select Register return 1; + if(!enable) { + if(writeRegister(0x0C, 0x00)) // Digital filter register: disable HPF on L&R Channels + return 1; + return 0; + } + // // Config Page 0 commands // diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index 212722d0f..fe07ec964 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -70,7 +70,7 @@ class I2c_Codec : public I2c, public AudioCodec ~I2c_Codec(); private: - int configureDCRemovalIIR(); //called by startAudio() + int configureDCRemovalIIR(bool enable); //called by startAudio() int codecType; int dacVolumeHalfDbs; int adcVolumeHalfDbs; From 374a004ed9aaf63a3756f9004f36b04b5a9f244d Mon Sep 17 00:00:00 2001 From: Andrew McPherson Date: Sat, 28 Dec 2019 23:33:14 +0000 Subject: [PATCH 008/148] Changed direction of frame sync so it is generated by McASP, not codec. Also added register read ability to I2c_Codec. (cherry picked from commit e3378d1d9b417f3476e5085a7f22157cf68778b9) --- core/I2c_Codec.cpp | 93 +++++++++++++++++++++++++++++-------- core/I2c_MultiTLVCodec.cpp | 37 +++++++++++++-- include/I2c_Codec.h | 6 ++- include/I2c_MultiTLVCodec.h | 4 ++ pru/pru_rtaudio_irq.p | 15 +++++- 5 files changed, 129 insertions(+), 26 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 70c63bf41..455ded2b8 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -18,7 +18,7 @@ I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, CodecType type, bool isVerbose /*= false*/) : codecType(type), dacVolumeHalfDbs(0), adcVolumeHalfDbs(0), hpVolumeHalfDbs(0), - master(true), running(false) + generatesBclk(true), generatesWclk(true), running(false) { setVerbose(isVerbose); initI2C_RW(i2cBus, i2cAddress, -1); @@ -46,13 +46,22 @@ int I2c_Codec::initCodec() // it runs at 44.1kHz int I2c_Codec::startAudio(int dual_rate) { - return startAudio(dual_rate, 1, 0, 16, 0); + return startAudio(dual_rate, 1, 1, 0, 16, 0); } -int I2c_Codec::startAudio(int dual_rate, int is_master, int tdm_mode, int slotSize, int startingSlot) -{ - master = is_master; +// Start audio with more setting control +// generates_bclk: whether the codec generates the bit clock from its PLL +// generates_wclk: whether the codec generates the frame sync +// tdm_mode: whether to use TDM rather than I2S mode +// slotSize: size of a slot in bits +// startingSlot: where in the TDM frame to place the first channel +int I2c_Codec::startAudio(int dual_rate, int generates_bclk, int generates_wclk, int tdm_mode, + int slotSize, int startingSlot) +{ + generatesBclk = generates_bclk; + generatesWclk = generates_wclk; + // As a best-practice it's safer not to assume the implementer has issued initCodec() // or has not otherwise modified codec registers since that call. // Explicit Switch to config register page 0: @@ -63,7 +72,7 @@ int I2c_Codec::startAudio(int dual_rate, int is_master, int tdm_mode, int slotSi if(writeRegister(0x02, 0x00)) // Codec sample rate register: fs_ref / 1 return 1; - if(is_master) { + if(generatesBclk) { // The sampling frequency is given as f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P) // The master clock PLLCLK_IN is 12MHz // K can be varied in intervals of resolution of 0.0001 up to 63.9999 @@ -76,8 +85,6 @@ int I2c_Codec::startAudio(int dual_rate, int is_master, int tdm_mode, int slotSi return 1; if(setAudioSamplingRate(44100)) //this will automatically find and set K for the given P and R so that Fs=44100 return 1; - - // TODO: check if anything needs to change for 256 clock mode } else { // Disable PLL: the codec will be clocked from the bit clock generated by another master @@ -95,18 +102,27 @@ int I2c_Codec::startAudio(int dual_rate, int is_master, int tdm_mode, int slotSi return 1; } - if(is_master) { - if(writeRegister(0x08, 0xE0)) // Audio serial control register A: BLCK, WCLK outputs, - return 1; // DOUT tri-state when inactive + if(generatesBclk) { + if(generatesWclk) { + if(writeRegister(0x08, 0xE0)) { // Audio serial control register A: BCLK, WCLK outputs, + return 1; // DOUT tri-state when inactive + } + } + else { + if(writeRegister(0x08, 0xA0)) { // Audio serial control register A: BCLK output, WCLK input, + return 1; // DOUT tri-state when inactive + } + } } else { - if(writeRegister(0x08, 0x20)) // Audio serial control register A: BLCK, WCLK inputs, + // If we don't generate the bit clock then we don't generate the word clock + if(writeRegister(0x08, 0x20)) // Audio serial control register A: BCLK, WCLK inputs, return 1; // DOUT tri-state when inactive } if(tdm_mode) { unsigned int crb; // Audio serial control register B - if(slotSize == 16) + if(slotSize == 16) // The below values all enable 256-clock mode when Bclk is an output crb = 0x48; else if(slotSize == 20) crb = 0x58; @@ -154,7 +170,7 @@ int I2c_Codec::startAudio(int dual_rate, int is_master, int tdm_mode, int slotSi if(writeHPVolumeRegisters()) // Send DAC to high-power outputs return 1; - if(is_master) { + if(generatesBclk) { if(writeRegister(0x66, 0x02)) // Clock generation control register: use MCLK, PLL N = 2 return 1; } @@ -180,7 +196,7 @@ int I2c_Codec::startAudio(int dual_rate, int is_master, int tdm_mode, int slotSi // wait for the codec to stabilize before unmuting the HP amp. // this gets rid of the loud pop. - if(is_master) + if(generatesBclk) usleep(10000); // note : a small click persists, but it is unavoidable @@ -194,7 +210,7 @@ int I2c_Codec::startAudio(int dual_rate, int is_master, int tdm_mode, int slotSi if(writeDACVolumeRegisters(false)) // Unmute and set volume return 1; - if(is_master) { + if(generatesBclk) { if(writeRegister(0x65, 0x00)) // GPIO control register B: disabled; codec uses PLLDIV_OUT return 1; } @@ -622,15 +638,54 @@ int I2c_Codec::writeRegister(unsigned int reg, unsigned int value) return 0; } +// Read a specific register on the codec +int I2c_Codec::readRegister(unsigned int reg) +{ + i2c_char_t inbuf, outbuf; + struct i2c_rdwr_ioctl_data packets; + struct i2c_msg messages[2]; + + /* Reading a register involves a repeated start condition which needs ioctl() */ + outbuf = reg; + messages[0].addr = i2C_address; + messages[0].flags = 0; + messages[0].len = sizeof(outbuf); + messages[0].buf = &outbuf; + + /* The data will get returned in this structure */ + messages[1].addr = i2C_address; + messages[1].flags = I2C_M_RD/* | I2C_M_NOSTART*/; + messages[1].len = sizeof(inbuf); + messages[1].buf = &inbuf; + + /* Send the request to the kernel and get the result back */ + packets.msgs = messages; + packets.nmsgs = 2; + if(ioctl(i2C_file, I2C_RDWR, &packets) < 0) { + verbose && fprintf(stderr, "Failed to read register %d on I2c codec\n", reg); + return -1; + } + + return inbuf; +} + // Put codec to Hi-z (required for CTAG face) int I2c_Codec::disable(){ if (writeRegister(0x0, 0)) // Select page 0 return 1; if(writeRegister(0x01, 0x80)) // Reset codec to defaults return 1; - if(master) { - if (writeRegister(0x08, 0xE0)) // Put codec in master mode (required for hi-z mode) - return 1; + if(generatesBclk) { + if(generatesWclk) { + if(writeRegister(0x08, 0xE0)) { // Put codec in master mode (required for hi-z mode) + return 1; + } + } + else { + if(writeRegister(0x08, 0xA0)) { + return 1; + } + } } else { if (writeRegister(0x08, 0x20)) // Leave codec in slave mode diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 5250c116a..8412b157c 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -13,17 +13,22 @@ #include #include "../include/I2c_MultiTLVCodec.h" +#undef CODEC_WCLK_MASTER // Match this with pru_rtaudio_irq.p + I2c_MultiTLVCodec::I2c_MultiTLVCodec(int i2cBus, int i2cAddress, bool isVerbose /*= false*/) : masterCodec(0), running(false), verbose(isVerbose) { // for(int address = i2cAddress + 3; address >= i2cAddress; address--) { for(int address = i2cAddress; address < i2cAddress + 4; address++) { // Check for presence of TLV codec and take the first one we find as the master codec - // TODO: this code assumes the first codec is a 3104 (Bela Mini cape), which might not always be true + // TODO: this code assumes the first codec is a 3104 (Bela Mini cape), which might not always be true I2c_Codec::CodecType type = (address == i2cAddress) ? I2c_Codec::TLV320AIC3104 : I2c_Codec::TLV320AIC3106; I2c_Codec *testCodec = new I2c_Codec(i2cBus, address, type); if(testCodec->initCodec() != 0) { delete testCodec; + if(verbose) { + fprintf(stderr, "Error initialising I2C codec on bus %d address %d\n", i2cBus, address); + } } else { // codec found @@ -70,14 +75,21 @@ int I2c_MultiTLVCodec::startAudio(int dual_rate) return 1; // Master codec generates the clocks with its PLL and occupies the first two slots - if((ret = masterCodec->startAudio(dual_rate, 1, 1, slotSize, 0))) +#ifdef CODEC_WCLK_MASTER + // Main codec generates word clock + if((ret = masterCodec->startAudio(dual_rate, 1, 1, 1, slotSize, 0))) return ret; +#else + // AM335x generates word clock + if((ret = masterCodec->startAudio(dual_rate, 1, 0, 1, slotSize, 0))) + return ret; +#endif // Each subsequent codec occupies the next 2 slots std::vector::iterator it; for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { slotNum += 2; - if((ret = (*it)->startAudio(dual_rate, 0, 1, slotSize, slotNum))) + if((ret = (*it)->startAudio(dual_rate, 0, 0, 1, slotSize, slotNum))) return ret; } @@ -220,6 +232,25 @@ int I2c_MultiTLVCodec::numDetectedCodecs() return extraCodecs.size() + 1; } +// For debugging purposes only! +void I2c_MultiTLVCodec::debugWriteRegister(int codecNum, int regNum, int value) { + if(codecNum == 0) { + masterCodec->writeRegister(regNum, value); + } + else { + extraCodecs[codecNum - 1]->writeRegister(regNum, value); + } +} + +int I2c_MultiTLVCodec::debugReadRegister(int codecNum, int regNum) { + if(codecNum == 0) { + return masterCodec->readRegister(regNum); + } + else { + return extraCodecs[codecNum - 1]->readRegister(regNum); + } +} + I2c_MultiTLVCodec::~I2c_MultiTLVCodec() { stopAudio(); diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index fe07ec964..8b572eb0a 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -33,10 +33,11 @@ class I2c_Codec : public I2c, public AudioCodec } CodecType; int writeRegister(unsigned int reg, unsigned int value); + int readRegister(unsigned int reg); int initCodec(); int startAudio(int dual_rate); - int startAudio(int dual_rate, int is_master, int tdm_mode, int slotSize, int startingSlot); + int startAudio(int dual_rate, int generates_bclk, int generates_wclk, int tdm_mode, int slotSize, int startingSlot); int stopAudio(); int setPllJ(short unsigned int j); @@ -75,7 +76,8 @@ class I2c_Codec : public I2c, public AudioCodec int dacVolumeHalfDbs; int adcVolumeHalfDbs; int hpVolumeHalfDbs; - bool master; + bool generatesBclk; + bool generatesWclk; bool running; bool verbose; bool hpEnabled; diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index 82afa52d1..bacd1bc75 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -12,6 +12,7 @@ #pragma once +#include #include "I2c_Codec.h" class I2c_MultiTLVCodec : public AudioCodec @@ -30,6 +31,9 @@ class I2c_MultiTLVCodec : public AudioCodec int numDetectedCodecs(); + void debugWriteRegister(int codecNum, int regNum, int value); + int debugReadRegister(int codecNum, int regNum); + I2c_MultiTLVCodec(int i2cBus, int i2cAddress, bool verbose = false); ~I2c_MultiTLVCodec(); diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 53bedb33a..3896b405c 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -22,6 +22,8 @@ #define CTAG_IGNORE_UNUSED_INPUT_TDM_SLOTS //#define MCASP_INPUTS_ARE_HALF_AS_MANY_AS_OUTPUTS // TODO: make it runtime (should not be there for BELA_TLV) +#undef CODEC_WCLK_MASTER // Match this with I2c_MultiTLVCodec.cpp + #define DBOX_CAPE // Define this to use new cape hardware #define CLOCK_BASE 0x44E00000 @@ -312,8 +314,12 @@ #define MCASP_PIN_AMUTE (1 << 25) // Also, 0 to 3 are XFR0 to XFR3 #ifdef DBOX_CAPE +#ifdef CODEC_WCLK_MASTER #define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 2) // AHCLKX and AXR2 outputs #else +#define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | MCASP_PIN_AFSX | (1 << 2) // AHCLKX, FSX, AXR2 outputs +#endif +#else #define MCASP_OUTPUT_PINS (1 << 3) // Which pins are outputs #endif @@ -373,8 +379,13 @@ #define BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE 0x00 // External clk, polarity (falling edge) #define BELA_MULTI_TLV_MCASP_AHCLKRCTL_VALUE MCASP_AHCLKRCTL_VALUE #define BELA_MULTI_TLV_MCASP_AHCLKXCTL_VALUE MCASP_AHCLKXCTL_VALUE -#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x800 // 16-slot TDM, rising edge means beginning of frame -#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x800 // 16-slot TDM, rising edge means beginning of frame +#ifdef CODEC_WCLK_MASTER +#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x800 // 16-slot TDM input, rising edge means beginning of frame +#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x800 // 16-slot TDM input, rising edge means beginning of frame +#else +#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x802 // 16-slot TDM output, rising edge means beginning of frame +#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x802 // 16-slot TDM output, rising edge means beginning of frame +#endif // RTDM and XTDM are calculated dynamically #define BELA_MULTI_TLV_MCASP_RINTCTL_VALUE MCASP_RINTCTL_VALUE #define BELA_MULTI_TLV_MCASP_XINTCTL_VALUE MCASP_XINTCTL_VALUE From d65162fc4d88eef3b5c40971069540762f77a7a5 Mon Sep 17 00:00:00 2001 From: Andrew McPherson Date: Sun, 29 Dec 2019 00:56:18 +0000 Subject: [PATCH 009/148] An empirical set of settings that produces (mostly) stable I/O -- but it shouldn't work according to the datasheet, and isn't 100% reliable. (cherry picked from commit 1efa3434c2dac4acb89013e4f0db94d3f9aeb1f3) --- pru/pru_rtaudio_irq.p | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 3896b405c..735fac434 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -374,17 +374,22 @@ // Values below are for 16x 16-bit TDM slots #define BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits -#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits -#define BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE 0x00 // External clk, polarity (falling edge) -#define BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE 0x00 // External clk, polarity (falling edge) +#define BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE 0x00 // External clk, polarity (falling edge) #define BELA_MULTI_TLV_MCASP_AHCLKRCTL_VALUE MCASP_AHCLKRCTL_VALUE #define BELA_MULTI_TLV_MCASP_AHCLKXCTL_VALUE MCASP_AHCLKXCTL_VALUE #ifdef CODEC_WCLK_MASTER +#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits +#define BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE 0x00 // External clk, polarity (falling edge) #define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x800 // 16-slot TDM input, rising edge means beginning of frame #define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x800 // 16-slot TDM input, rising edge means beginning of frame #else -#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x802 // 16-slot TDM output, rising edge means beginning of frame -#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x802 // 16-slot TDM output, rising edge means beginning of frame +// The settings below shouldn't work according to the datasheet, but in practice this +// combination does work, perhaps due to a signal quality issue with the high-speed bit clock (?) +// The datasheet would suggest 0x8074, 0x00 and 0x802 respectively. +#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x18074 // MSB first, 1 bit delay, 16 bits, CFG bus, ROR 16bits +#define BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE 0x80 // External clk, polarity (rising edge) +#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x803 // 16-slot TDM output, falling edge means beginning of frame +#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x803 // 16-slot TDM output, falling edge means beginning of frame #endif // RTDM and XTDM are calculated dynamically #define BELA_MULTI_TLV_MCASP_RINTCTL_VALUE MCASP_RINTCTL_VALUE From d040fd0ad8e74fb165a853c4e5b9968267a8a85d Mon Sep 17 00:00:00 2001 From: Andrew McPherson Date: Thu, 2 Jan 2020 00:33:06 +0000 Subject: [PATCH 010/148] Go back to recommended McASP settings -- looks like this is more reliable if the signal quality issue can be sorted (cherry picked from commit ba6900ab9e74023a4a0bc36d4029a5ae9f5d50b6) --- pru/pru_rtaudio_irq.p | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 735fac434..9bad32c78 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -386,10 +386,14 @@ // The settings below shouldn't work according to the datasheet, but in practice this // combination does work, perhaps due to a signal quality issue with the high-speed bit clock (?) // The datasheet would suggest 0x8074, 0x00 and 0x802 respectively. -#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x18074 // MSB first, 1 bit delay, 16 bits, CFG bus, ROR 16bits -#define BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE 0x80 // External clk, polarity (rising edge) -#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x803 // 16-slot TDM output, falling edge means beginning of frame -#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x803 // 16-slot TDM output, falling edge means beginning of frame +// #define BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x18074 // MSB first, 1 bit delay, 16 bits, CFG bus, ROR 16bits +// #define BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE 0x80 // External clk, polarity (rising edge) +// #define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x803 // 16-slot TDM output, falling edge means beginning of frame +// #define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x803 // 16-slot TDM output, falling edge means beginning of frame +#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits +#define BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE 0x00 // External clk, polarity (falling edge) +#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x802 // 16-slot TDM output, rising edge means beginning of frame +#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x802 // 16-slot TDM output, rising edge means beginning of frame #endif // RTDM and XTDM are calculated dynamically #define BELA_MULTI_TLV_MCASP_RINTCTL_VALUE MCASP_RINTCTL_VALUE From dadd20ed815d18eae3009161b8691ec8cfa97030 Mon Sep 17 00:00:00 2001 From: Andrew McPherson Date: Fri, 17 Jan 2020 17:15:45 +0000 Subject: [PATCH 011/148] Updated PRU IRQ code to work on Bela Mini (with or without multi-codec) (cherry picked from commit 1281de7fff79929756c071d2972b6966036bdc48) --- pru/pru_rtaudio_irq.p | 68 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 9bad32c78..dd1d0f6ca 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -579,7 +579,7 @@ DONE: LSL DEST, DEST, 1 .endm -QBA START // when first starting, go to START, skipping this section. +QBA START_INTERMEDIATE // when first starting, go to START, skipping this section. DIGITAL: //IMPORTANT: do NOT use r28 in this macro, as it contains the return address for JAL @@ -599,9 +599,28 @@ DIGITAL: //r8 will contain GPIO1_SETDATAOUT MOV r8, 0 MOV r7, 0 -//map GPIO_ANALOG to gpio1 pins, +//map GPIO to gpio1 pins, //r2 is gpio1_oe, r8 is gpio1_setdataout, r7 is gpio1_cleardataout, r27 is the input word //the following operations will read from r27 and update r2,r7,r8 +QBBS BELA_SET_GPIO_BITS_0_MINI, reg_flags, FLAG_BIT_BELA_MINI +QBBS BELA_SET_GPIO_BITS_0_MINI, reg_flags, FLAG_BIT_BELA_MULTI_TLV +QBA BELA_SET_GPIO_BITS_0_NOT_MINI +BELA_SET_GPIO_BITS_0_MINI: + SET_GPIO_BITS r2, r8, r7, 18, 0, r27 + SET_GPIO_BITS r2, r8, r7, 27, 1, r27 + SET_GPIO_BITS r2, r8, r7, 26, 2, r27 + SET_GPIO_BITS r2, r8, r7, 25, 3, r27 + SET_GPIO_BITS r2, r8, r7, 28, 4, r27 + SET_GPIO_BITS r2, r8, r7, 20, 5, r27 + SET_GPIO_BITS r2, r8, r7, 15, 6, r27 + SET_GPIO_BITS r2, r8, r7, 14, 8, r27 + SET_GPIO_BITS r2, r8, r7, 12, 9, r27 + SET_GPIO_BITS r2, r8, r7, 9, 10, r27 + SET_GPIO_BITS r2, r8, r7, 8, 11, r27 + SET_GPIO_BITS r2, r8, r7, 10, 14, r27 + SET_GPIO_BITS r2, r8, r7, 11, 15, r27 +QBA SET_GPIO_BITS_0_DONE +BELA_SET_GPIO_BITS_0_NOT_MINI: SET_GPIO_BITS r2, r8, r7, 13, 4, r27 SET_GPIO_BITS r2, r8, r7, 12, 5, r27 SET_GPIO_BITS r2, r8, r7, 28, 6, r27 @@ -609,6 +628,7 @@ DIGITAL: SET_GPIO_BITS r2, r8, r7, 15, 8, r27 SET_GPIO_BITS r2, r8, r7, 14, 9, r27 SET_GPIO_BITS r2, r8, r7, 19, 10, r27 +SET_GPIO_BITS_0_DONE: //set the output enable register for gpio1. MOV r3, GPIO1 | GPIO_OE //use r3 as a temp register SBBO r2, r3, 0, 4 //takes two cycles (10ns) @@ -626,9 +646,18 @@ DIGITAL: //r5 will contain GPIO2_SETDATAOUT MOV r5, 0 MOV r4, 0 -//map GPIO_ANALOG to gpio2 pins +//map GPIO to gpio2 pins //r3 is gpio2_oe, r5 is gpio2_setdataout, r4 is gpio2_cleardataout, r27 is the input word //the following operations will read from r27 and update r3,r4,r5 +QBBS BELA_SET_GPIO_BITS_1_MINI, reg_flags, FLAG_BIT_BELA_MINI +QBBS BELA_SET_GPIO_BITS_1_MINI, reg_flags, FLAG_BIT_BELA_MULTI_TLV +QBA BELA_SET_GPIO_BITS_1_NOT_MINI +BELA_SET_GPIO_BITS_1_MINI: + SET_GPIO_BITS r3, r5, r4, 0, 7, r27 + SET_GPIO_BITS r3, r5, r4, 22, 12, r27 + SET_GPIO_BITS r3, r5, r4, 24, 13, r27 + QBA SET_GPIO_BITS_1_DONE +BELA_SET_GPIO_BITS_1_NOT_MINI: SET_GPIO_BITS r3, r5, r4, 2, 0, r27 SET_GPIO_BITS r3, r5, r4, 3, 1, r27 SET_GPIO_BITS r3, r5, r4, 5, 2, r27 @@ -638,12 +667,18 @@ DIGITAL: SET_GPIO_BITS r3, r5, r4, 24, 13, r27 SET_GPIO_BITS r3, r5, r4, 23, 14, r27 SET_GPIO_BITS r3, r5, r4, 25, 15, r27 +SET_GPIO_BITS_1_DONE: //set the output enable register for gpio2. MOV r2, GPIO2 | GPIO_OE //use r2 as a temp registerp SBBO r3, r2, 0, 4 //takes two cycles (10ns) //GPIO2-end //r3 is now unused +QBA START_INTERMEDIATE_DONE +START_INTERMEDIATE: // intermediate step to jump to START + QBA START +START_INTERMEDIATE_DONE: + //load current inputs in r2, r3 //r2 will contain GPIO1_DATAIN //r3 will contain GPIO2_DATAIN @@ -656,7 +691,30 @@ DIGITAL: LBBO r3, r3, 0, 4 //now read from r2 and r3 only the channels that are set as input in the lower word of r27 // and set their value in the high word of r27 +QBBS BELA_READ_GPIO_BITS_MINI, reg_flags, FLAG_BIT_BELA_MINI +QBBS BELA_READ_GPIO_BITS_MINI, reg_flags, FLAG_BIT_BELA_MULTI_TLV +QBA BELA_READ_GPIO_BITS_NOT_MINI +BELA_READ_GPIO_BITS_MINI: //GPIO1 + READ_GPIO_BITS r2, 18, 0, r27 + READ_GPIO_BITS r2, 27, 1, r27 + READ_GPIO_BITS r2, 26, 2, r27 + READ_GPIO_BITS r2, 25, 3, r27 + READ_GPIO_BITS r2, 28, 4, r27 + READ_GPIO_BITS r2, 20, 5, r27 + READ_GPIO_BITS r2, 15, 6, r27 + READ_GPIO_BITS r2, 14, 8, r27 + READ_GPIO_BITS r2, 12, 9, r27 + READ_GPIO_BITS r2, 9, 10, r27 + READ_GPIO_BITS r2, 8, 11, r27 + READ_GPIO_BITS r2, 10, 14, r27 + READ_GPIO_BITS r2, 11, 15, r27 +//GPIO2 + READ_GPIO_BITS r3, 0, 7, r27 + READ_GPIO_BITS r3, 22, 12, r27 + READ_GPIO_BITS r3, 24, 13, r27 + QBA READ_GPIO_BITS_DONE +BELA_READ_GPIO_BITS_NOT_MINI: READ_GPIO_BITS r2, 13, 4, r27 READ_GPIO_BITS r2, 12, 5, r27 READ_GPIO_BITS r2, 28, 6, r27 @@ -674,6 +732,7 @@ DIGITAL: READ_GPIO_BITS r3, 24, 13, r27 READ_GPIO_BITS r3, 23, 14, r27 READ_GPIO_BITS r3, 25, 15, r27 +READ_GPIO_BITS_DONE: //r2, r3 are now unused //now all the setdataout and cleardataout are ready to be written to the GPIO register. @@ -1109,6 +1168,7 @@ DIGITAL_INIT_BUFFER_LOOP: ADD r3, r3, 4 //increment pointer QBGT DIGITAL_INIT_BUFFER_LOOP, r3, r4 //loop until we reach the end of the buffer */ + DIGITAL_INIT_DONE: // Check if we should use an external multiplexer capelet // The valid values are 0 (off), 1 (2 ch), 2 (4 ch), 3 (8 ch) @@ -2356,7 +2416,7 @@ MUX_CHANNEL_SAVE_DONE: QBEQ LED_BLINK_DONE, r3, 0 MOV r1, 0x1000 AND r2, r2, r1 // Test (frame count & 4096) - QBEQ LED_BLINK_OFF, r2, 0 + QBEQ LED_BLINK_OFF, r2, 0 LBBO r2, reg_comm_addr, COMM_LED_PIN_MASK, 4 MOV r1, GPIO_SETDATAOUT ADD r3, r3, r1 // Address for GPIO set register From 5322997472c1978a95fab8a9f9e83c54de365330 Mon Sep 17 00:00:00 2001 From: Andrew McPherson Date: Fri, 17 Jan 2020 17:29:16 +0000 Subject: [PATCH 012/148] Add support to PRU IRQ code for Bela Mini ADC CS line. however, analog input still does not work on this code. (cherry picked from commit 2dda62b8baeab0cd1b8dfe376addd54252766d54) --- pru/pru_rtaudio_irq.p | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index dd1d0f6ca..701432460 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -106,10 +106,13 @@ #ifdef DBOX_CAPE #define ADC_GPIO GPIO1 #define ADC_CS_PIN (1<<16) // GPIO1:16 = P9 pin 15 -#else +// for BELA_MINI, this is the same as DAC_CS_PIN, but the latter is disabled in DAC_WRITE +#define ADC_GPIO_BELA_MINI GPIO0 +#define ADC_CS_PIN_BELA_MINI (1<<5) // GPIO1:5 = P1 pin 6 +#else /* DBOX_CAPE */ #define ADC_GPIO GPIO1 #define ADC_CS_PIN (1<<17) // GPIO1:17 = P9 pin 23 -#endif +#endif /* DBOX_CAPE */ #define ADC_TRM 0 // SPI transmit and receive #define ADC_WL 16 // Word length #define ADC_CLK_MODE 0 // SPI mode @@ -502,6 +505,14 @@ MOV r31.b0, PRU_SYSTEM_EVENT_RTDM_WRITE_VALUE QBBS DEST, reg_flags, FLAG_BIT_BELA_MULTI_TLV .endm +.macro BELA_MINI_OR_MULTI_TLV_OR_JMP_TO +.mparam DEST + QBBS DONE, reg_flags, FLAG_BIT_BELA_MINI + QBBS DONE, reg_flags, FLAG_BIT_BELA_MULTI_TLV + QBA DEST +DONE: +.endm + .macro CTAG_OR_JMP_TO .mparam DEST QBBC DEST, reg_flags, FLAG_BIT_CTAG @@ -833,15 +844,27 @@ DAC_CHANNEL_REORDER_DONE: // Bring CS line low to write to ADC .macro ADC_CS_ASSERT + BELA_MINI_OR_MULTI_TLV_OR_JMP_TO BELA + MOV r27, ADC_CS_PIN_BELA_MINI + MOV r28, ADC_GPIO_BELA_MINI + GPIO_CLEARDATAOUT + QBA DONE +BELA: MOV r27, ADC_CS_PIN MOV r28, ADC_GPIO + GPIO_CLEARDATAOUT +DONE: SBBO r27, r28, 0, 4 .endm // Bring CS line high at end of ADC transaction .macro ADC_CS_UNASSERT + BELA_MINI_OR_MULTI_TLV_OR_JMP_TO BELA + MOV r27, ADC_CS_PIN_BELA_MINI + MOV r28, ADC_GPIO_BELA_MINI + GPIO_SETDATAOUT + QBA DONE +BELA: MOV r27, ADC_CS_PIN MOV r28, ADC_GPIO + GPIO_SETDATAOUT +DONE: SBBO r27, r28, 0, 4 .endm @@ -1616,7 +1639,9 @@ INNER_EVENT_LOOP: MOV r27, (1 << FLAG_BIT_MCASP_TX_PROCESSED) OR r27, r27, (1 << FLAG_BIT_MCASP_RX_PROCESSED) AND r27, r27, reg_flags - QBEQ NEXT_FRAME, r27, 0x60 + QBNE NOT_NEXT_FRAME, r27, 0x60 + JMP NEXT_FRAME +NOT_NEXT_FRAME: // Check if ARM says should finish: flag is zero as long as it should run LBBO r27, reg_comm_addr, COMM_SHOULD_STOP, 4 @@ -2376,8 +2401,9 @@ BELA_MULTI_TLV_ANALOG_CFG_END: SET_REG_FRAMES_DONE: ADD reg_frame_current, reg_frame_current, 1 - QBNE EVENT_LOOP, reg_frame_current, r14 - + QBEQ ALL_FRAMES_PROCESSED, reg_frame_current, r14 + JMP EVENT_LOOP + ALL_FRAMES_PROCESSED: // Now done, swap the buffers and do the next one // Use r2 as a temp register From bfd8a9e2ccf6fb61a92e7931e416454b6f0d36b3 Mon Sep 17 00:00:00 2001 From: Andrew McPherson Date: Sat, 18 Jan 2020 23:46:46 +0000 Subject: [PATCH 013/148] Skip DAC CS on Bela Mini for IRQ PRU code (cherry picked from commit d1eb9acdf87d8b7c8f0320a390efbd37dd6bc0d1) --- pru/pru_rtaudio_irq.p | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 701432460..7b66d1614 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -805,10 +805,16 @@ QBA DALOOP // Complete DAC write with chip select .macro DAC_WRITE .mparam reg + QBBS SKIP_DAC_WRITE_1, reg_flags, FLAG_BIT_BELA_MINI + QBBS SKIP_DAC_WRITE_1, reg_flags, FLAG_BIT_BELA_MULTI_TLV DAC_CS_ASSERT +SKIP_DAC_WRITE_1: DAC_TX reg DAC_WAIT_FOR_FINISH + QBBS SKIP_DAC_WRITE_2, reg_flags, FLAG_BIT_BELA_MINI + QBBS SKIP_DAC_WRITE_2, reg_flags, FLAG_BIT_BELA_MULTI_TLV DAC_CS_UNASSERT +SKIP_DAC_WRITE_2: DAC_DISCARD_RX .endm From ade1f9d2f8d5d901b1f50274b34298bce397f728 Mon Sep 17 00:00:00 2001 From: Andrew McPherson Date: Sat, 18 Jan 2020 23:55:58 +0000 Subject: [PATCH 014/148] Fixed ADC memory location in PRU IRQ code on Bela Mini (cherry picked from commit 9b6962954789569ce1326d9c7d924a0dd446cf1d) --- pru/pru_rtaudio_irq.p | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 7b66d1614..c2fdd1a5e 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -1590,10 +1590,16 @@ WRITE_ONE_BUFFER: // Write a single buffer of DAC samples and read a buffer of ADC samples // Load starting positions MOV reg_dac_current, reg_dac_buf0 // DAC: reg_dac_current is current pointer - LMBD r2, reg_num_channels, 1 // 1, 2 or 3 for 2, 4 or 8 channels + LMBD r2, reg_num_channels, 1 // 1, 2 or 3 for 2, 4 or 8 channels +BELA_MINI_OR_MULTI_TLV_OR_JMP_TO BELA_CHANNELS + // there are 0 dac values, so ADC starts at the same point as DAC + MOV reg_adc_current, reg_dac_current + QBA CHANNELS_DONE +BELA_CHANNELS: LSL reg_adc_current, reg_frame_spi_total, r2 LSL reg_adc_current, reg_adc_current, 2 // N * 2 * 2 * bufsize ADD reg_adc_current, reg_adc_current, reg_dac_current // ADC: starts N * 2 * 2 * bufsize beyond DAC +CHANNELS_DONE: MOV reg_mcasp_dac_current, reg_mcasp_buf0 // McASP: set current DAC pointer // the CTAGs only use half as many input channels as there are outputs, so divide by 2 (LSR by 1) when computing offsets // if I/O buffers are the same size, then McASP ADC: starts (N/2)*2bytes*bufsize beyond DAC From 47c005d3d2846e270e4347b3e345d308448c391c Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Thu, 26 Mar 2020 19:44:55 +0000 Subject: [PATCH 015/148] Cleaned up pru_rtaudio.p --- pru/pru_rtaudio.p | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pru/pru_rtaudio.p b/pru/pru_rtaudio.p index db9b969e3..734b45226 100644 --- a/pru/pru_rtaudio.p +++ b/pru/pru_rtaudio.p @@ -216,34 +216,32 @@ #define MCASP_AFSCTL_VALUE 0x101 // 2-slot TDM I2S mode, falling edge means beginning of frame #define MCASP_DATA_FORMAT_VALUE 0x1807C // MSB first, 1 bit delay, 16 bits, CFG bus, ROR 16bits #define MCASP_ACLKXCTL_VALUE 0x80 // Transmit on rising edge, sync. xmit and recv -#define MCASP_TDM_VALUE 0x03 // Enable TDM slots 0 and 1 #endif #ifdef TLV320_MODE_DSP #define MCASP_AFSCTL_VALUE 0x100 // 2-slot TDM I2S mode, rising edge means beginning of frame #define MCASP_ACLKXCTL_VALUE 0x00 // Transmit on falling edge, sync. xmit and recv #define MCASP_DATA_FORMAT_VALUE 0x807C // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits -#define MCASP_TDM_VALUE 0x03 // Enable TDM slots 0 and 1 #endif #ifdef TLV320_MODE_TDM + #ifdef MCASP_SLOT_16BITS #define MCASP_AFSCTL_VALUE 0x800 // 16-slot TDM, rising edge means beginning of frame #define MCASP_DATA_FORMAT_VALUE 0x807C // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits -#endif +#endif // MCASP_SLOT_16BITS #ifdef MCASP_SLOT_32BITS #define MCASP_AFSCTL_VALUE 0x400 // 8-slot TDM, rising edge means beginning of frame #define MCASP_DATA_FORMAT_VALUE 0x80F8 // MSB first, 0 bit delay, 32 bits, CFG bus, ROR 0bits -#endif +#endif // MCASP_SLOT_32BITS // 20 and 24 bit slots not supported in 256-cycle TDM // Hypothetically, for 20 bits, MCASP_DATA_FORMAT_VALUE = 0x809B // Hypothetically, for 24 bits, MCASP_DATA_FORMAT_VALUE = 0x80BA #define MCASP_ACLKXCTL_VALUE 0x00 // Transmit on falling edge, sync. xmit and recv -#define MCASP_TDM_VALUE 0x03 // Enable TDM slots 0 and 1 -#endif +#endif // TLV320_MODE_TDM #define C_MCASP_MEM C28 // Shared PRU mem From 5f65dfe566afaea3b137fd8520da413685713c66 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Thu, 26 Mar 2020 20:07:44 +0000 Subject: [PATCH 016/148] Cleanup of stale comments and refactored --- pru/pru_rtaudio_irq.p | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index c2fdd1a5e..9b91caeeb 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -380,21 +380,12 @@ #define BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE 0x00 // External clk, polarity (falling edge) #define BELA_MULTI_TLV_MCASP_AHCLKRCTL_VALUE MCASP_AHCLKRCTL_VALUE #define BELA_MULTI_TLV_MCASP_AHCLKXCTL_VALUE MCASP_AHCLKXCTL_VALUE -#ifdef CODEC_WCLK_MASTER #define BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits #define BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE 0x00 // External clk, polarity (falling edge) +#ifdef CODEC_WCLK_MASTER #define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x800 // 16-slot TDM input, rising edge means beginning of frame #define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x800 // 16-slot TDM input, rising edge means beginning of frame #else -// The settings below shouldn't work according to the datasheet, but in practice this -// combination does work, perhaps due to a signal quality issue with the high-speed bit clock (?) -// The datasheet would suggest 0x8074, 0x00 and 0x802 respectively. -// #define BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x18074 // MSB first, 1 bit delay, 16 bits, CFG bus, ROR 16bits -// #define BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE 0x80 // External clk, polarity (rising edge) -// #define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x803 // 16-slot TDM output, falling edge means beginning of frame -// #define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x803 // 16-slot TDM output, falling edge means beginning of frame -#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits -#define BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE 0x00 // External clk, polarity (falling edge) #define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x802 // 16-slot TDM output, rising edge means beginning of frame #define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x802 // 16-slot TDM output, rising edge means beginning of frame #endif From d22e5f4e1d5d73b58551117b872ea22209554df0 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Thu, 26 Mar 2020 20:17:18 +0000 Subject: [PATCH 017/148] multi-codec: Handling BelaMiniMultiAudio --- core/RTAudio.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 5feacfd47..e9adddbdd 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -523,6 +523,9 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) case BelaHw_Salt: fifoFactor = settings->periodSize / 128; break; + case BelaHw_BelaMiniMultiAudio: + //TODO: we are assuming 6 in / 6 out + //nobreak case BelaHw_CtagFace: //nobreak case BelaHw_CtagFaceBela: From 449baefcc0ea23b1dc579afa7a94c262236d66e4 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 27 Mar 2020 18:31:04 +0000 Subject: [PATCH 018/148] actually working pru_rtaudio.p --- pru/pru_rtaudio.p | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pru/pru_rtaudio.p b/pru/pru_rtaudio.p index 734b45226..5773adf82 100644 --- a/pru/pru_rtaudio.p +++ b/pru/pru_rtaudio.p @@ -210,7 +210,7 @@ #define MCASP_DATA_MASK 0xFFFFFFFF // 32 bit data #endif -#define TLV320_MODE_TDM +#define TLV320_MODE_DSP #ifdef TLV320_MODE_I2S #define MCASP_AFSCTL_VALUE 0x101 // 2-slot TDM I2S mode, falling edge means beginning of frame From d6be3f6567b0db26be72e5d74c6380bf2fccf5e1 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 20 Jul 2020 17:52:01 +0000 Subject: [PATCH 019/148] I2c_Codec: make transmitSyncBitDelay explicit --- core/I2c_Codec.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 455ded2b8..d218f7580 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -133,9 +133,10 @@ int I2c_Codec::startAudio(int dual_rate, int generates_bclk, int generates_wclk, else return 1; + unsigned int transmitSyncBitDelay = 0; if(writeRegister(0x09, crb)) // Audio serial control register B: DSP mode, word len specified by slotSize return 1; - if(writeRegister(0x0A, startingSlot*slotSize)) // Audio serial control register C: specifying offset in bits + if(writeRegister(0x0A, startingSlot * slotSize + transmitSyncBitDelay)) // Audio serial control register C: specifying offset in bits return 1; } else { From 6d947c5455a8ae80ca3e9d1617081cb0658ca57a Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 27 Mar 2020 19:08:35 +0000 Subject: [PATCH 020/148] board_detect and core: Bela_hwContains() can be used to test for the presence of components in a BelaHw. Accordingly refactored/simplified codebase --- core/PRU.cpp | 12 +++--- core/RTAudio.cpp | 83 ++++++++++-------------------------------- core/board_detect.cpp | 69 +++++++++++++++++++++++++++-------- include/board_detect.h | 12 ++++++ 4 files changed, 91 insertions(+), 85 deletions(-) diff --git a/core/PRU.cpp b/core/PRU.cpp index 4cf9245a9..d10af2387 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -21,6 +21,7 @@ #include "../include/Bela.h" #include "../include/Gpio.h" #include "../include/PruArmCommon.h" +#include "../include/board_detect.h" #include #include @@ -73,6 +74,7 @@ static int rtdm_fd_mcasp_to_pru = 0; #include "../include/xenomai_wraps.h" using namespace std; +using namespace BelaHwComponent; // Select whether to use NEON-based sample conversion // (this will probably go away in a future commit once its performance @@ -309,7 +311,7 @@ int PRU::prepareGPIO(int include_led) } if(context->digitalFrames != 0){ - if(belaHw == BelaHw_BelaMini || belaHw == BelaHw_BelaMiniMultiAudio) + if(Bela_hwContains(belaHw, PocketBeagle)) { gDigitalPins = digitalPinsPocketBeagle; } else { @@ -334,7 +336,7 @@ int PRU::prepareGPIO(int include_led) } if(include_led) { - if(belaHw == BelaHw_BelaMini || belaHw == BelaHw_BelaMiniMultiAudio) + if(Bela_hwContains(belaHw, BelaMiniCape)) { //using on-board LED gpio_export(belaMiniLedBlue); @@ -377,7 +379,7 @@ void PRU::cleanupGPIO() } } if(led_enabled) { - if(belaHw == BelaHw_BelaMini || belaHw == BelaHw_BelaMiniMultiAudio) + if(Bela_hwContains(belaHw, BelaMiniCape)) { //using on-board LED gpio_unexport(belaMiniLedBlue); @@ -421,7 +423,7 @@ int PRU::initialise(BelaHw newBelaHw, int pru_num, bool uniformSampleRate, int m if(0 <= stopButtonPin){ stopButton.open(stopButtonPin, Gpio::INPUT, false); } - if((belaHw == BelaHw_BelaMini || belaHw == BelaHw_BelaMiniMultiAudio) && enableLed){ + if(Bela_hwContains(belaHw, BelaMiniCape) && enableLed){ underrunLed.open(belaMiniLedRed, Gpio::OUTPUT); underrunLed.clear(); } @@ -645,7 +647,7 @@ void PRU::initialisePruCommon() } if(led_enabled) { - if(belaHw == BelaHw_BelaMini || belaHw == BelaHw_BelaMiniMultiAudio) + if(Bela_hwContains(belaHw, BelaMiniCape)) { pru_buffer_comm[PRU_LED_ADDRESS] = belaMiniLedBlueGpioBase; pru_buffer_comm[PRU_LED_PIN_MASK] = belaMiniLedBlueGpioPinMask; diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index e9adddbdd..0cafc6ef4 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -112,6 +112,7 @@ void sigdebug_handler(int sig, siginfo_t *si, void *context) } #endif // XENOMAI_CATCH_MSW using namespace std; +using namespace BelaHwComponent; typedef struct { @@ -131,41 +132,16 @@ static int Bela_getHwConfigPrivate(BelaHw hw, BelaHwConfig* cfg, BelaHwConfigPri printf("Bela_getHwConfigPrivate()\n"); memset((void*)cfg, 0, sizeof(BelaHwConfig)); cfg->digitalChannels = 16; - // set audio codec - AudioCodec* activeCodec; - AudioCodec* disabledCodec; - switch(hw) + // set audio codec (order of the below statements is important) + if(pcfg) { - case BelaHw_Bela: - //nobreak - case BelaHw_BelaMini: - //nobreak - case BelaHw_Salt: - //nobreak - activeCodec = gI2cCodec; - disabledCodec = gSpiCodec; - break; - case BelaHw_BelaMiniMultiAudio: - cfg->activeCodec = gI2cMultiTLVCodec; - cfg->disabledCodec = gSpiCodec; - break; - case BelaHw_CtagFace: - //nobreak - case BelaHw_CtagFaceBela: - //nobreak - case BelaHw_CtagBeast: - //nobreak - case BelaHw_CtagBeastBela: - activeCodec = gSpiCodec; - disabledCodec = gI2cCodec; - break; - case BelaHw_NoHw: - default: - return -1; // unrecognized hw - } - if(pcfg) { - pcfg->activeCodec = activeCodec; - pcfg->disabledCodec = disabledCodec; + if(Bela_hwContains(hw, CtagCape)) { + pcfg->activeCodec = gSpiCodec; + pcfg->disabledCodec = gI2cCodec; + } else if (Bela_hwContains(hw, Tlv320aic3104)) { + pcfg->activeCodec = gI2cCodec; + pcfg->disabledCodec = gSpiCodec; + } } // set audio I/O switch(hw) @@ -215,30 +191,11 @@ static int Bela_getHwConfigPrivate(BelaHw hw, BelaHwConfig* cfg, BelaHwConfigPri return -1; // unrecognized hw } // set analogs: - switch(hw) - { - case BelaHw_Bela: - //nobreak - case BelaHw_Salt: - //nobreak - case BelaHw_CtagFaceBela: - //nobreak - case BelaHw_CtagBeastBela: - cfg->analogInChannels = 8; - cfg->analogOutChannels = 8; - break; - case BelaHw_BelaMiniMultiAudio: - case BelaHw_BelaMini: - cfg->analogInChannels = 8; - break; - case BelaHw_CtagFace: - //nobreak - case BelaHw_CtagBeast: - //nobreak - case BelaHw_NoHw: - //nobreak - default: - break; + if(Bela_hwContains(hw, BelaCape)) { + cfg->analogInChannels = 8; + cfg->analogOutChannels = 8; + } else if(Bela_hwContains(hw, BelaMiniCape)) { + cfg->analogInChannels = 8; } return 0; } @@ -490,14 +447,12 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) printf("Hardware to be used: %s\n", getBelaHwName(belaHw).c_str()); // TODO: this is a bit dirty here, it should probably be in getHwConfig, which should probably contextually renamed - if(belaHw == BelaHw_CtagFace || belaHw == BelaHw_CtagFaceBela) + if(1 == Bela_hwContains(belaHw, CtagCape)) gSpiCodec = new Spi_Codec(ctagSpidevGpioCs0, NULL); - else if(belaHw == BelaHw_CtagBeast || belaHw == BelaHw_CtagBeastBela) + else if(2 == Bela_hwContains(belaHw, CtagCape)) gSpiCodec = new Spi_Codec(ctagSpidevGpioCs0, ctagSpidevGpioCs1); - if(belaHw != BelaHw_CtagBeast && belaHw != BelaHw_CtagFace && belaHw != BelaHw_BelaMiniMultiAudio) - gI2cCodec = new I2c_Codec(codecI2cBus, codecI2cAddress, I2c_Codec::TLV320AIC3104, gRTAudioVerbose); - if(belaHw == BelaHw_BelaMiniMultiAudio) - gI2cMultiTLVCodec = new I2c_MultiTLVCodec(codecI2cBus, codecI2cAddress, gRTAudioVerbose); + else + gI2cCodec = new I2c_Codec(codecI2cBus, codecI2cAddress, I2c_Codec::TLV320AIC3104, gRTAudioVerbose); BelaHwConfig cfg; BelaHwConfigPrivate pcfg; diff --git a/core/board_detect.cpp b/core/board_detect.cpp index 42a47fc9f..8303dbbbe 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -260,27 +260,64 @@ BelaHw Bela_detectUserHw() return BelaHw_NoHw; } +using namespace BelaHwComponent; bool Bela_checkHwCompatibility(BelaHw userHw, BelaHw detectedHw) { - if(userHw == BelaHw_Bela && - (detectedHw == BelaHw_Bela || detectedHw == BelaHw_CtagFaceBela || detectedHw == BelaHw_CtagBeastBela)) - { + if(userHw == BelaHw_Bela && Bela_hwContains(detectedHw, BelaCape)) return true; - } - else if(userHw == BelaHw_CtagFace && - (detectedHw == BelaHw_CtagBeast || detectedHw == BelaHw_CtagFaceBela|| detectedHw == BelaHw_CtagBeastBela)) - { + else if(userHw == BelaHw_CtagFace && Bela_hwContains(detectedHw, CtagCape)) return true; - } - else if(userHw == BelaHw_CtagBeast && - detectedHw == BelaHw_CtagBeastBela) - { + else if(userHw == BelaHw_CtagBeast && 2 == Bela_hwContains(detectedHw, CtagCape)) return true; - } - else if(userHw == BelaHw_Salt && - detectedHw == BelaHw_Bela) - { + else if(userHw == BelaHw_Salt && Bela_hwContains(detectedHw, BelaCape)) + return true; + else if (userHw == BelaHw_BelaMini && Bela_hwContains(detectedHw, BelaMiniCape)) return true; - } return false; } + +unsigned int Bela_hwContains(const BelaHw hw, const BelaHwComponent::Component component) +{ + switch(component) { + case BelaCape: + switch(hw) { + case BelaHw_Bela: + case BelaHw_Salt: + case BelaHw_CtagFaceBela: + case BelaHw_CtagBeastBela: + return 1; + default: + return 0; + } + break; + case BelaMiniCape: + switch(hw) { + case BelaHw_BelaMini: + return 1; + default: + return 0; + } + break; + case CtagCape: + switch(hw) { + case BelaHw_CtagFace: + case BelaHw_CtagFaceBela: + return 1; + case BelaHw_CtagBeastBela: + case BelaHw_CtagBeast: + return 2; + default: + return 0; + } + break; + case PocketBeagle: + return Bela_hwContains(hw, BelaMiniCape); + break; + case BeagleBoneBlack: + return Bela_hwContains(hw, BelaCape) || Bela_hwContains(hw, CtagCape); + break; + case Tlv320aic3104: + return Bela_hwContains(hw, BelaCape) || Bela_hwContains(hw, BelaMiniCape); + break; + } +} diff --git a/include/board_detect.h b/include/board_detect.h index 8393d4653..735284cd6 100644 --- a/include/board_detect.h +++ b/include/board_detect.h @@ -1,7 +1,19 @@ #pragma once #include "Bela.h" +#include +namespace BelaHwComponent { +typedef enum { + BelaCape, + BelaMiniCape, + CtagCape, + PocketBeagle, + BeagleBoneBlack, + Tlv320aic3104, +} Component; +} BelaHw Bela_detectUserHw(); bool Bela_checkHwCompatibility(BelaHw userHw, BelaHw detectedHw); BelaHw getBelaHw(std::string board); std::string getBelaHwName(BelaHw hardware); +unsigned int Bela_hwContains(BelaHw hw, BelaHwComponent::Component component); From 53ee9ef75a023a9b002d3ea3e326d8909262f0ca Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 20 Jul 2020 17:55:42 +0000 Subject: [PATCH 021/148] BelaMiniMultiAudio: re-added support --- core/RTAudio.cpp | 9 ++++++--- core/board_detect.cpp | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 0cafc6ef4..4870485a0 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -135,7 +135,10 @@ static int Bela_getHwConfigPrivate(BelaHw hw, BelaHwConfig* cfg, BelaHwConfigPri // set audio codec (order of the below statements is important) if(pcfg) { - if(Bela_hwContains(hw, CtagCape)) { + if(BelaHw_BelaMiniMultiAudio == hw) { + cfg->activeCodec = gI2cMultiTLVCodec; + cfg->disabledCodec = gSpiCodec; + } else if(Bela_hwContains(hw, CtagCape)) { pcfg->activeCodec = gSpiCodec; pcfg->disabledCodec = gI2cCodec; } else if (Bela_hwContains(hw, Tlv320aic3104)) { @@ -427,8 +430,6 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) // Initialise the rendering environment: sample rates, frame counts, numbers of channels BelaHw belaHw = Bela_detectHw(); - // belaHw = BelaHw_BelaMini; - // belaHw = BelaHw_BelaMiniMultiAudio; // TESTING if(gRTAudioVerbose) printf("Detected hardware: %s\n", getBelaHwName(belaHw).c_str()); // Check for user-selected hardware @@ -451,6 +452,8 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) gSpiCodec = new Spi_Codec(ctagSpidevGpioCs0, NULL); else if(2 == Bela_hwContains(belaHw, CtagCape)) gSpiCodec = new Spi_Codec(ctagSpidevGpioCs0, ctagSpidevGpioCs1); + else if(belaHw == BelaHw_BelaMiniMultiAudio) + gI2cMultiTLVCodec = new I2c_MultiTLVCodec(codecI2cBus, codecI2cAddress, gRTAudioVerbose); else gI2cCodec = new I2c_Codec(codecI2cBus, codecI2cAddress, I2c_Codec::TLV320AIC3104, gRTAudioVerbose); diff --git a/core/board_detect.cpp b/core/board_detect.cpp index 8303dbbbe..63a68195a 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -293,6 +293,7 @@ unsigned int Bela_hwContains(const BelaHw hw, const BelaHwComponent::Component c case BelaMiniCape: switch(hw) { case BelaHw_BelaMini: + case BelaHw_BelaMiniMultiAudio: return 1; default: return 0; From c5c88280b89cea4403a11569366e7a5ce8ee1a6c Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 27 Mar 2020 19:45:36 +0000 Subject: [PATCH 022/148] bitDelay is available as a parameter. Minor refactoring to improve readability --- core/I2c_Codec.cpp | 10 +++++----- core/I2c_MultiTLVCodec.cpp | 19 +++++++++++-------- include/I2c_Codec.h | 2 +- include/I2c_MultiTLVCodec.h | 2 +- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index d218f7580..9dcd22ab5 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -46,7 +46,7 @@ int I2c_Codec::initCodec() // it runs at 44.1kHz int I2c_Codec::startAudio(int dual_rate) { - return startAudio(dual_rate, 1, 1, 0, 16, 0); + return startAudio(dual_rate, true, true, false, 16, 0, 0); } // Start audio with more setting control @@ -56,8 +56,9 @@ int I2c_Codec::startAudio(int dual_rate) // slotSize: size of a slot in bits // startingSlot: where in the TDM frame to place the first channel -int I2c_Codec::startAudio(int dual_rate, int generates_bclk, int generates_wclk, int tdm_mode, - int slotSize, int startingSlot) +int I2c_Codec::startAudio(bool dual_rate, bool generates_bclk, bool generates_wclk, + bool tdm_mode, unsigned int slotSize, unsigned int startingSlot, + unsigned int bitDelay) { generatesBclk = generates_bclk; generatesWclk = generates_wclk; @@ -133,10 +134,9 @@ int I2c_Codec::startAudio(int dual_rate, int generates_bclk, int generates_wclk, else return 1; - unsigned int transmitSyncBitDelay = 0; if(writeRegister(0x09, crb)) // Audio serial control register B: DSP mode, word len specified by slotSize return 1; - if(writeRegister(0x0A, startingSlot * slotSize + transmitSyncBitDelay)) // Audio serial control register C: specifying offset in bits + if(writeRegister(0x0A, startingSlot * slotSize + bitDelay)) // Audio serial control register C: specifying offset in bits return 1; } else { diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 8412b157c..2c27cb8bc 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -68,28 +68,31 @@ int I2c_MultiTLVCodec::startAudio(int dual_rate) // Supported values of slot size in the PRU code: 16 and 32 bits. Note that // altering slot size requires changing #defines in the PRU code. const int slotSize = 16; - int slotNum = 0; - int ret = 0; + unsigned int slotNum = 0; + unsigned int bitDelay = 0; + int ret; if(!masterCodec) return 1; - // Master codec generates the clocks with its PLL and occupies the first two slots + bool codecWclkMaster = #ifdef CODEC_WCLK_MASTER // Main codec generates word clock - if((ret = masterCodec->startAudio(dual_rate, 1, 1, 1, slotSize, 0))) - return ret; + true; #else // AM335x generates word clock - if((ret = masterCodec->startAudio(dual_rate, 1, 0, 1, slotSize, 0))) - return ret; + false; #endif + // Master codec generates bclk (and possibly wclk) with its PLL + // and occupies the first two slots + if((ret = masterCodec->startAudio(dual_rate, true, codecWclkMaster, true, slotSize, slotNum, bitDelay))) + return ret; // Each subsequent codec occupies the next 2 slots std::vector::iterator it; for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { slotNum += 2; - if((ret = (*it)->startAudio(dual_rate, 0, 0, 1, slotSize, slotNum))) + if((ret = (*it)->startAudio(dual_rate, false, false, true, slotSize, slotNum, bitDelay))) return ret; } diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index 8b572eb0a..d97505c43 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -37,7 +37,7 @@ class I2c_Codec : public I2c, public AudioCodec int initCodec(); int startAudio(int dual_rate); - int startAudio(int dual_rate, int generates_bclk, int generates_wclk, int tdm_mode, int slotSize, int startingSlot); + int startAudio(bool dual_rate, bool generates_bclk, bool generates_wclk, bool tdm_mode, unsigned int slotSize, unsigned int startingSlot, unsigned int bitDelay); int stopAudio(); int setPllJ(short unsigned int j); diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index bacd1bc75..aaefb7c8a 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -43,4 +43,4 @@ class I2c_MultiTLVCodec : public AudioCodec bool running; bool verbose; -}; \ No newline at end of file +}; From 5440b5efe073c2dce583d1abd3333fbf259e2ce8 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Sat, 28 Mar 2020 13:38:14 +0000 Subject: [PATCH 023/148] Allow to run BelaMini as BelaMiniMultiAudio --- core/board_detect.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/board_detect.cpp b/core/board_detect.cpp index 63a68195a..bf6e8cb0d 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -273,6 +273,8 @@ bool Bela_checkHwCompatibility(BelaHw userHw, BelaHw detectedHw) return true; else if (userHw == BelaHw_BelaMini && Bela_hwContains(detectedHw, BelaMiniCape)) return true; + else if (userHw == BelaHw_BelaMiniMultiAudio && Bela_hwContains(detectedHw, BelaMiniCape)) + return true; return false; } From 6a31f0c484ff640532ad67da46354e4b22bfec5a Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 30 Mar 2020 11:25:31 +0000 Subject: [PATCH 024/148] PRU: Factored error codes out to PruArmCommon.h, and handling ARM_ERROR_INVALID_INIT as critical --- core/PRU.cpp | 20 +++++++++++--------- include/PruArmCommon.h | 8 ++++++++ pru/pru_rtaudio_irq.p | 6 ------ 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/core/PRU.cpp b/core/PRU.cpp index d10af2387..691bb74ba 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -207,13 +207,6 @@ class PruMemory #define PRU_ERROR_OCCURRED 17 #define PRU_ACTIVE_TDM_SLOTS 18 -// error codes sent from the PRU -#define ARM_ERROR_TIMEOUT 1 -#define ARM_ERROR_XUNDRUN 2 -#define ARM_ERROR_XSYNCERR 3 -#define ARM_ERROR_XCKFAIL 4 -#define ARM_ERROR_XDMAERR 5 - static unsigned int* gDigitalPins = NULL; #define USERLED3_GPIO_BASE (Gpio::getBankAddress(1))// GPIO1(24) is user LED 3 @@ -853,6 +846,10 @@ int PRU::testPruError() verbose && rt_fprintf(stderr, "PRU event loop timed out\n"); ret = 1; break; + case ARM_ERROR_INVALID_INIT: + fprintf(stderr, "Invalid PRU configuration settings\n"); + ret = 2; + break; default: verbose && rt_fprintf(stderr, "Unknown PRU error: %d\n", errorCode); ret = 1; @@ -916,6 +913,7 @@ void PRU::loop(void *userData, void(*render)(BelaContext*, void*), bool highPerf int underrunLedCount = -1; while(!Bela_stopRequested()) { + int error = 0; #if defined BELA_USE_POLL || defined BELA_USE_BUSYWAIT // Which buffer the PRU was last processing static uint32_t lastPRUBuffer = 0; @@ -924,7 +922,7 @@ void PRU::loop(void *userData, void(*render)(BelaContext*, void*), bool highPerf #ifdef BELA_USE_POLL task_sleep_ns(sleepTime); #endif /* BELA_USE_POLL */ - if(testPruError()) + if(error = testPruError()) { break; } @@ -937,7 +935,11 @@ void PRU::loop(void *userData, void(*render)(BelaContext*, void*), bool highPerf if(!highPerformanceMode) // unless the user requested us not to. task_sleep_ns(sleepTime / 2); int ret = __wrap_read(rtdm_fd_pru_to_arm, NULL, 0); - testPruError(); + error = testPruError(); + if(2 == error) { + gShouldStop = true; + break; + } if(ret < 0) { static int interruptTimeoutCount = 0; diff --git a/include/PruArmCommon.h b/include/PruArmCommon.h index d980313b1..1ba92231e 100644 --- a/include/PruArmCommon.h +++ b/include/PruArmCommon.h @@ -11,4 +11,12 @@ #define PRU_SYS_EV_MCASP_RX_INTR 54 // mcasp_r_intr_pend #define PRU_SYS_EV_MCASP_TX_INTR 55 // mcasp_x_intr_pend +// error codes sent from the PRU +#define ARM_ERROR_TIMEOUT 1 +#define ARM_ERROR_XUNDRUN 2 +#define ARM_ERROR_XSYNCERR 3 +#define ARM_ERROR_XCKFAIL 4 +#define ARM_ERROR_XDMAERR 5 +#define ARM_ERROR_INVALID_INIT 6 + #endif /* PRU_ARM_COMMON_H */ diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 9b91caeeb..831d231c8 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -144,12 +144,6 @@ #define COMM_ERROR_OCCURED 68 // Signals the ARM CPU that an error happened #define COMM_ACTIVE_TDM_SLOTS 72 // How many TDM slots contain useful data -#define ARM_ERROR_TIMEOUT 1 -#define ARM_ERROR_XUNDRUN 2 -#define ARM_ERROR_XSYNCERR 3 -#define ARM_ERROR_XCKFAIL 4 -#define ARM_ERROR_XDMAERR 5 - // General constants for local PRU peripherals (used for interrupt configuration) #define PRU_ICSS_INTC_LOCAL 0x00020000 #define PRU_ICSS_CFG_LOCAL 0x00026000 From 88a4285c40c88acc88f942b076c577adf95f7ccc Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 30 Mar 2020 12:24:55 +0000 Subject: [PATCH 025/148] PRU: NOP, tidying up whitespaces a bit, cleaning out stale comments --- pru/pru_rtaudio_irq.p | 96 +++++++++++++------------------------------ 1 file changed, 28 insertions(+), 68 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 831d231c8..23b769bff 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -376,6 +376,7 @@ #define BELA_MULTI_TLV_MCASP_AHCLKXCTL_VALUE MCASP_AHCLKXCTL_VALUE #define BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits #define BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE 0x00 // External clk, polarity (falling edge) + #ifdef CODEC_WCLK_MASTER #define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x800 // 16-slot TDM input, rising edge means beginning of frame #define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x800 // 16-slot TDM input, rising edge means beginning of frame @@ -383,6 +384,7 @@ #define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x802 // 16-slot TDM output, rising edge means beginning of frame #define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x802 // 16-slot TDM output, rising edge means beginning of frame #endif + // RTDM and XTDM are calculated dynamically #define BELA_MULTI_TLV_MCASP_RINTCTL_VALUE MCASP_RINTCTL_VALUE #define BELA_MULTI_TLV_MCASP_XINTCTL_VALUE MCASP_XINTCTL_VALUE @@ -423,10 +425,10 @@ #define reg_digital_current r6 // Pointer to current storage location of DIGITAL #define reg_num_channels r9 // Number of SPI ADC/DAC channels to use #define reg_frame_current r10 // Current frame count in SPI ADC/DAC transfer -#define reg_frame_mcasp_total r11 // Total frame count for SPI ADC/DAC +#define reg_frame_mcasp_total r11 // Total frame count for McASP #define reg_dac_data r12 // Current dword for SPI DAC #define reg_adc_data r13 // Current dword for SPI ADC -#define reg_frame_spi_total r15 // Current dword for McASP ADC +#define reg_frame_spi_total r15 // Current dword for SPI ADC/DAC #define reg_dac_buf0 r16 // Start pointer to SPI DAC buffer 0 #define reg_dac_buf1 r17 // Start pointer to SPI DAC buffer 1 #define reg_dac_current r18 // Pointer to current storage location of SPI DAC @@ -570,7 +572,7 @@ DONE: .macro READ_MULTI_TLV_CHANNELS .mparam DEST LSR DEST, reg_flags, FLAG_BIT_AUDIO_CHANNELS0 - AND DEST, DEST, 0x0F + AND DEST, DEST, 0x0F ADD DEST, DEST, 1 LSL DEST, DEST, 1 .endm @@ -1466,16 +1468,9 @@ WRITE_FRAME_MULTI_TLV: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 BELA_MULTI_TLV_OR_JMP_TO WRITE_FRAME_NOT_MULTI_TLV - - - // TLVTODO TESTNG - //MCASP_WRITE_TO_DATAPORT 0x00, 4 - //MCASP_WRITE_TO_DATAPORT 0x00, 4 - //QBA WRITE_FRAME_NOT_MULTI_TLV - - READ_MULTI_TLV_CHANNELS r2 // How many channels? + READ_MULTI_TLV_CHANNELS r2 // How many channels? WRITE_FRAME_MULTI_TLV_LOOP: - MCASP_WRITE_TO_DATAPORT 0x00, 4 // Write 4 bytes for each channel + MCASP_WRITE_TO_DATAPORT 0x00, 4 // Write 4 bytes for each channel SUB r2, r2, 1 QBNE WRITE_FRAME_MULTI_TLV_LOOP, r2, 0 @@ -1487,7 +1482,7 @@ MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 4) // Set RFRST MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 12) // Set XFRST // Initialisation - LBBO reg_frame_mcasp_total, reg_comm_addr, COMM_BUFFER_MCASP_FRAMES, 4 // Total frame count (0.5x-2x for McASP) + LBBO reg_frame_mcasp_total, reg_comm_addr, COMM_BUFFER_MCASP_FRAMES, 4 // Total frame count for McASP LBBO reg_frame_spi_total, reg_comm_addr, COMM_BUFFER_SPI_FRAMES, 4 // Total frame count for SPI MOV reg_dac_buf0, 0 // DAC buffer 0 start pointer LSL reg_dac_buf1, reg_frame_spi_total, 1 // DAC buffer 1 start pointer = N[ch]*2[bytes]*bufsize @@ -1575,7 +1570,7 @@ WRITE_ONE_BUFFER: // Write a single buffer of DAC samples and read a buffer of ADC samples // Load starting positions MOV reg_dac_current, reg_dac_buf0 // DAC: reg_dac_current is current pointer - LMBD r2, reg_num_channels, 1 // 1, 2 or 3 for 2, 4 or 8 channels + LMBD r2, reg_num_channels, 1 // 1, 2 or 3 for 2, 4 or 8 channels BELA_MINI_OR_MULTI_TLV_OR_JMP_TO BELA_CHANNELS // there are 0 dac values, so ADC starts at the same point as DAC MOV reg_adc_current, reg_dac_current @@ -1650,11 +1645,10 @@ NOT_NEXT_FRAME: // an interrupt, an error must have occurred SEND_ERROR_TO_ARM ARM_ERROR_TIMEOUT JMP START // TODO: should HALT and wait for ARM to restart - + GO_TO_CLEANUP: JMP CLEANUP - - + MCASP_CHECK_TX_ERROR_END: QBBC INNER_EVENT_LOOP, r31, PRU_INTR_BIT_CH1 @@ -1755,32 +1749,21 @@ BELA_NOT_MULTI_TLV_OR_JMP_TO LOAD_AUDIO_FRAME_MULTI_TLV LOAD_AUDIO_FRAME_MULTI_TLV: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 -BELA_MULTI_TLV_OR_JMP_TO LOAD_AUDIO_FRAME_NOT_MULTI_TLV - - // TLVTODO TESTING - //LBCO r0, C_MCASP_MEM, reg_mcasp_dac_current, 4 - //SBCO r8, C_MCASP_MEM, reg_mcasp_dac_current, 4 - //ADD reg_mcasp_dac_current, reg_mcasp_dac_current, 4 - //QBA LOAD_AUDIO_FRAME_NOT_MULTI_TLV - + BELA_MULTI_TLV_OR_JMP_TO LOAD_AUDIO_FRAME_NOT_MULTI_TLV // Number of bytes to load depends on number of active TDM slots - // LBCO/SBCO only support r0 as indicator of number of bytes - // so load begins from r1 - LDI r16, 0 - - // TLVTODO: this only works up to 16 channels based on number of registers - READ_MULTI_TLV_CHANNELS r0 - QBGT LOAD_AUDIO_FRAME_MULTI_TLV_LT16CHAN, r0, 16 - LDI r0, 16 + // LBCO/SBCO only support r0 as indicator of number of bytes + // so load begins from r1 + LDI r16, 0 + + // TLVTODO: this only works up to 16 channels based on number of registers + READ_MULTI_TLV_CHANNELS r0 + QBGT LOAD_AUDIO_FRAME_MULTI_TLV_LT16CHAN, r0, 16 + LDI r0, 16 LOAD_AUDIO_FRAME_MULTI_TLV_LT16CHAN: - LSL r0, r0, 1 // 16 bits per channel + LSL r0, r0, 1 // 16 bits per channel LBCO r1, C_MCASP_MEM, reg_mcasp_dac_current, b0 SBCO r9, C_MCASP_MEM, reg_mcasp_dac_current, b0 - ADD reg_mcasp_dac_current, reg_mcasp_dac_current, r0.b0 - -// MOV r0, r1 // TLVTODO TESTING -// MOV r8, r9 - + ADD reg_mcasp_dac_current, reg_mcasp_dac_current, r0.b0 LOAD_AUDIO_FRAME_NOT_MULTI_TLV: #endif /* ENABLE_BELA_MULTI_TLV32 */ LOAD_AUDIO_FRAME_DONE: @@ -1810,7 +1793,7 @@ CTAG_BEAST_OR_JMP_TO WRITE_AUDIO_FRAME_NOT_CTAG_BEAST // but 24 registers need to be free for use AND r8, r17, r0 LSR r9, r0, 16 - AND r10, r17, r1 + AND r10, r17, r1 LSR r11, r1, 16 AND r12, r17, r2 LSR r13, r2, 16 @@ -1834,23 +1817,11 @@ WRITE_AUDIO_FRAME_NOT_CTAG_BEAST: BELA_NOT_MULTI_TLV_OR_JMP_TO WRITE_AUDIO_FRAME_MULTI_TLV AND r8, r17, r0 LSR r9, r0, 16 - MCASP_WRITE_TO_DATAPORT r8, 8 WRITE_AUDIO_FRAME_MULTI_TLV: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 BELA_MULTI_TLV_OR_JMP_TO WRITE_AUDIO_FRAME_NOT_MULTI_TLV - - - // TLVTODO TESTING - //AND r8, r17, r0 - //LSR r9, r0, 16 - - //LDI r8, 0 - //LDI r9, 0xFFFF - //MCASP_WRITE_TO_DATAPORT r8, 8 - //QBA WRITE_AUDIO_FRAME_NOT_MULTI_TLV - AND r9, r17, r1 LSR r10, r1, 16 MCASP_WRITE_TO_DATAPORT r9, 8 @@ -2017,17 +1988,6 @@ FRAME_READ_MULTI_TLV: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 BELA_MULTI_TLV_OR_JMP_TO FRAME_READ_NOT_MULTI_TLV - - // TLVTODO TESTING - - //MCASP_READ_FROM_DATAPORT r8, 32 - //AND r0, r8, r17 - //LSL r16, r9, 16 - //OR r0, r0, r16 - - //SBCO r0, C_MCASP_MEM, reg_mcasp_adc_current, 4 // store result - //ADD reg_mcasp_adc_current, reg_mcasp_adc_current, 4 // increment memory pointer - //QBA FRAME_READ_NOT_MULTI_TLV // END TLVTODO TESTING @@ -2311,7 +2271,7 @@ MCSPI_INTR_RX1_FULL: NEXT_FRAME: - CLR reg_flags, reg_flags, FLAG_BIT_MCASP_TX_PROCESSED + CLR reg_flags, reg_flags, FLAG_BIT_MCASP_TX_PROCESSED CLR reg_flags, reg_flags, FLAG_BIT_MCASP_RX_PROCESSED #ifdef ENABLE_CTAG_FACE @@ -2390,7 +2350,7 @@ BELA_MULTI_TLV_ANALOG_8: // Eight channels LSL r14, reg_frame_spi_total, 1 JMP BELA_MULTI_TLV_ANALOG_CFG_END BELA_MULTI_TLV_ANALOG_2: // Two channels - LSR r14, reg_frame_spi_total, 1 + LSR r14, reg_frame_spi_total, 1 BELA_MULTI_TLV_ANALOG_CFG_END: #endif /* ENABLE_BELA_MULTI_TLV32 */ @@ -2399,8 +2359,8 @@ SET_REG_FRAMES_DONE: ADD reg_frame_current, reg_frame_current, 1 QBEQ ALL_FRAMES_PROCESSED, reg_frame_current, r14 - JMP EVENT_LOOP - + JMP EVENT_LOOP + ALL_FRAMES_PROCESSED: // Now done, swap the buffers and do the next one // Use r2 as a temp register @@ -2439,7 +2399,7 @@ MUX_CHANNEL_SAVE_DONE: QBEQ LED_BLINK_DONE, r3, 0 MOV r1, 0x1000 AND r2, r2, r1 // Test (frame count & 4096) - QBEQ LED_BLINK_OFF, r2, 0 + QBEQ LED_BLINK_OFF, r2, 0 LBBO r2, reg_comm_addr, COMM_LED_PIN_MASK, 4 MOV r1, GPIO_SETDATAOUT ADD r3, r3, r1 // Address for GPIO set register From 6482d16d2cf3c26e4a1340314de9ebc2f10d5c97 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 30 Mar 2020 16:26:30 +0000 Subject: [PATCH 026/148] PRU: mostly renaming things for clarity, but also adding some QBA for safety --- pru/pru_rtaudio_irq.p | 66 +++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 23b769bff..f14bceb50 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -492,14 +492,22 @@ MOV r31.b0, PRU_SYSTEM_EVENT_RTDM_WRITE_VALUE QBBS DEST, reg_flags, FLAG_BIT_BELA_MULTI_TLV .endm -.macro BELA_MINI_OR_MULTI_TLV_OR_JMP_TO +.macro IF_NOT_BELA_TLV32_JMP_TO .mparam DEST - QBBS DONE, reg_flags, FLAG_BIT_BELA_MINI - QBBS DONE, reg_flags, FLAG_BIT_BELA_MULTI_TLV - QBA DEST + QBBS DEST, reg_flags, FLAG_BIT_BELA_MULTI_TLV + QBBS DEST, reg_flags, FLAG_BIT_CTAG DONE: .endm +.macro IF_HAS_ANALOG_DAC_JMP_TO +.mparam DEST + QBBS DONE, reg_flags, FLAG_BIT_BELA_MINI + QBBS DONE, reg_flags, FLAG_BIT_BELA_MULTI_TLV + QBA DEST +DONE: +.endm +#define IF_HAS_BELA_SPI_ADC_CS_JMP_TO IF_HAS_ANALOG_DAC_JMP_TO + .macro CTAG_OR_JMP_TO .mparam DEST QBBC DEST, reg_flags, FLAG_BIT_CTAG @@ -837,11 +845,11 @@ DAC_CHANNEL_REORDER_DONE: // Bring CS line low to write to ADC .macro ADC_CS_ASSERT - BELA_MINI_OR_MULTI_TLV_OR_JMP_TO BELA + IF_HAS_BELA_SPI_ADC_CS_JMP_TO BELA_CS MOV r27, ADC_CS_PIN_BELA_MINI MOV r28, ADC_GPIO_BELA_MINI + GPIO_CLEARDATAOUT QBA DONE -BELA: +BELA_CS: MOV r27, ADC_CS_PIN MOV r28, ADC_GPIO + GPIO_CLEARDATAOUT DONE: @@ -850,11 +858,11 @@ DONE: // Bring CS line high at end of ADC transaction .macro ADC_CS_UNASSERT - BELA_MINI_OR_MULTI_TLV_OR_JMP_TO BELA + IF_HAS_BELA_SPI_ADC_CS_JMP_TO BELA_CS MOV r27, ADC_CS_PIN_BELA_MINI MOV r28, ADC_GPIO_BELA_MINI + GPIO_SETDATAOUT QBA DONE -BELA: +BELA_CS: MOV r27, ADC_CS_PIN MOV r28, ADC_GPIO + GPIO_SETDATAOUT DONE: @@ -1571,7 +1579,7 @@ WRITE_ONE_BUFFER: // Load starting positions MOV reg_dac_current, reg_dac_buf0 // DAC: reg_dac_current is current pointer LMBD r2, reg_num_channels, 1 // 1, 2 or 3 for 2, 4 or 8 channels -BELA_MINI_OR_MULTI_TLV_OR_JMP_TO BELA_CHANNELS +IF_HAS_ANALOG_DAC_JMP_TO BELA_CHANNELS // there are 0 dac values, so ADC starts at the same point as DAC MOV reg_adc_current, reg_dac_current QBA CHANNELS_DONE @@ -1742,11 +1750,12 @@ CTAG_BEAST_OR_JMP_TO LOAD_AUDIO_FRAME_NOT_CTAG_BEAST LOAD_AUDIO_FRAME_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ #ifdef ENABLE_BELA_TLV32 -BELA_NOT_MULTI_TLV_OR_JMP_TO LOAD_AUDIO_FRAME_MULTI_TLV + IF_NOT_BELA_TLV32_JMP_TO LOAD_AUDIO_FRAME_NOT_BELA_TLV32 LBCO r0, C_MCASP_MEM, reg_mcasp_dac_current, 4 SBCO r8, C_MCASP_MEM, reg_mcasp_dac_current, 4 ADD reg_mcasp_dac_current, reg_mcasp_dac_current, 4 -LOAD_AUDIO_FRAME_MULTI_TLV: + QBA LOAD_AUDIO_FRAME_DONE +LOAD_AUDIO_FRAME_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 BELA_MULTI_TLV_OR_JMP_TO LOAD_AUDIO_FRAME_NOT_MULTI_TLV @@ -1764,8 +1773,11 @@ LOAD_AUDIO_FRAME_MULTI_TLV_LT16CHAN: LBCO r1, C_MCASP_MEM, reg_mcasp_dac_current, b0 SBCO r9, C_MCASP_MEM, reg_mcasp_dac_current, b0 ADD reg_mcasp_dac_current, reg_mcasp_dac_current, r0.b0 + QBA LOAD_AUDIO_FRAME_DONE LOAD_AUDIO_FRAME_NOT_MULTI_TLV: #endif /* ENABLE_BELA_MULTI_TLV32 */ + SEND_ERROR_TO_ARM ARM_ERROR_INVALID_INIT + HALT LOAD_AUDIO_FRAME_DONE: //TODO: Change data structure in RAM to 32 bit samples @@ -1814,11 +1826,11 @@ CTAG_BEAST_OR_JMP_TO WRITE_AUDIO_FRAME_NOT_CTAG_BEAST WRITE_AUDIO_FRAME_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ #ifdef ENABLE_BELA_TLV32 -BELA_NOT_MULTI_TLV_OR_JMP_TO WRITE_AUDIO_FRAME_MULTI_TLV +IF_NOT_BELA_TLV32_JMP_TO WRITE_AUDIO_FRAME_NOT_BELA_TLV32 AND r8, r17, r0 LSR r9, r0, 16 MCASP_WRITE_TO_DATAPORT r8, 8 -WRITE_AUDIO_FRAME_MULTI_TLV: +WRITE_AUDIO_FRAME_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 BELA_MULTI_TLV_OR_JMP_TO WRITE_AUDIO_FRAME_NOT_MULTI_TLV @@ -1975,7 +1987,7 @@ SKIP_AUDIO_RX_FRAME: FRAME_READ_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ #ifdef ENABLE_BELA_TLV32 - BELA_NOT_MULTI_TLV_OR_JMP_TO FRAME_READ_MULTI_TLV + IF_NOT_BELA_TLV32_JMP_TO FRAME_READ_NOT_BELA_TLV32 MCASP_READ_FROM_DATAPORT r8, 32 AND r0, r8, r17 @@ -1984,7 +1996,7 @@ FRAME_READ_NOT_CTAG_BEAST: SBCO r0, C_MCASP_MEM, reg_mcasp_adc_current, 4 // store result ADD reg_mcasp_adc_current, reg_mcasp_adc_current, 4 // increment memory pointer -FRAME_READ_MULTI_TLV: +FRAME_READ_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 BELA_MULTI_TLV_OR_JMP_TO FRAME_READ_NOT_MULTI_TLV @@ -2320,31 +2332,33 @@ CTAG_BEAST_16CH_ANALOG_CFG_END: SET_REG_FRAMES_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ #ifdef ENABLE_BELA_TLV32 -BELA_NOT_MULTI_TLV_OR_JMP_TO BELA_TLV_ANALOG_CFG_END +IF_NOT_BELA_TLV32_JMP_TO SET_REG_FRAMES_NOT_BELA_TLV32 // Set reg frames total based on number of analog channels // 8 analog ch => LSL 1 // 4 analog ch => no shifting // 2 analog ch => LSR 1 - QBEQ BELA_TLV_ANALOG_8, reg_num_channels, 0x8 - QBEQ BELA_TLV_ANALOG_CFG_END, reg_num_channels, 0x4 - QBEQ BELA_TLV_ANALOG_2, reg_num_channels, 0x2 + QBEQ BELA_TLV32_ANALOG_8, reg_num_channels, 0x8 + QBEQ BELA_TLV32_ANALOG_CFG_END, reg_num_channels, 0x4 + QBEQ BELA_TLV32_ANALOG_2, reg_num_channels, 0x2 -BELA_TLV_ANALOG_8: // Eight channels +BELA_TLV32_ANALOG_8: // Eight channels LSL r14, reg_frame_mcasp_total, 1 - JMP BELA_TLV_ANALOG_CFG_END -BELA_TLV_ANALOG_2: // Two channels + JMP BELA_TLV32_ANALOG_CFG_END +BELA_TLV32_ANALOG_2: // Two channels LSR r14, reg_frame_mcasp_total, 1 -BELA_TLV_ANALOG_CFG_END: +BELA_TLV32_ANALOG_CFG_END: + QBA SET_REG_FRAMES_DONE +SET_REG_FRAMES_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 -BELA_MULTI_TLV_OR_JMP_TO BELA_MULTI_TLV_ANALOG_CFG_END +BELA_MULTI_TLV_OR_JMP_TO SET_REG_FRAMES_NOT_BELA_MULTI_TLV // Set reg frames total based on number of analog channels // 8 analog ch => LSL 1 // 4 analog ch => no shifting // 2 analog ch => LSR 1 QBEQ BELA_MULTI_TLV_ANALOG_8, reg_num_channels, 0x8 QBEQ BELA_MULTI_TLV_ANALOG_CFG_END, reg_num_channels, 0x4 - QBEQ BELA_MULTI_TLV_ANALOG_8, reg_num_channels, 0x2 + QBEQ BELA_MULTI_TLV_ANALOG_2, reg_num_channels, 0x2 BELA_MULTI_TLV_ANALOG_8: // Eight channels LSL r14, reg_frame_spi_total, 1 @@ -2353,6 +2367,8 @@ BELA_MULTI_TLV_ANALOG_2: // Two channels LSR r14, reg_frame_spi_total, 1 BELA_MULTI_TLV_ANALOG_CFG_END: + QBA SET_REG_FRAMES_DONE +SET_REG_FRAMES_NOT_BELA_MULTI_TLV: #endif /* ENABLE_BELA_MULTI_TLV32 */ SET_REG_FRAMES_DONE: From 9cc15ae1afa99774f3245188f29a97804453790c Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 30 Mar 2020 17:23:47 +0000 Subject: [PATCH 027/148] PRU: using IF_NOT_BELA_TLV32_JMP_TO instead of BELA_NOT_MULTI_TLV_OR_JMP_TO as it is more accurate (also covers CTAG cases) --- pru/pru_rtaudio_irq.p | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index f14bceb50..3453a5973 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -487,11 +487,6 @@ MOV r31.b0, PRU_SYSTEM_EVENT_RTDM_WRITE_VALUE QBBC DEST, reg_flags, FLAG_BIT_BELA_MULTI_TLV .endm -.macro BELA_NOT_MULTI_TLV_OR_JMP_TO -.mparam DEST - QBBS DEST, reg_flags, FLAG_BIT_BELA_MULTI_TLV -.endm - .macro IF_NOT_BELA_TLV32_JMP_TO .mparam DEST QBBS DEST, reg_flags, FLAG_BIT_BELA_MULTI_TLV @@ -1336,9 +1331,9 @@ MCASP_SET_RX_NOT_CTAG_FACE: MCASP_SET_RX_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ #ifdef ENABLE_BELA_TLV32 - BELA_NOT_MULTI_TLV_OR_JMP_TO MCASP_SET_RX_MULTI_TLV + IF_NOT_BELA_TLV32_JMP_TO MCASP_SET_RX_NOT_BELA_TLV32 MCASP_SET_RX BELA_TLV_MCASP_DATA_FORMAT_RX_VALUE, BELA_TLV_MCASP_AFSRCTL_VALUE, BELA_TLV_MCASP_ACLKRCTL_VALUE, BELA_TLV_MCASP_AHCLKRCTL_VALUE, BELA_TLV_MCASP_RTDM_VALUE, BELA_TLV_MCASP_RINTCTL_VALUE, MCASP_DATA_MASK -MCASP_SET_RX_MULTI_TLV: +MCASP_SET_RX_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 BELA_MULTI_TLV_OR_JMP_TO MCASP_SET_RX_NOT_MULTI_TLV @@ -1382,9 +1377,9 @@ MCASP_SET_TX_NOT_CTAG_FACE: MCASP_SET_TX_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ #ifdef ENABLE_BELA_TLV32 - BELA_NOT_MULTI_TLV_OR_JMP_TO MCASP_SET_TX_MULTI_TLV + IF_NOT_BELA_TLV32_JMP_TO MCASP_SET_TX_NOT_BELA_TLV32 MCASP_SET_TX BELA_TLV_MCASP_DATA_FORMAT_TX_VALUE, BELA_TLV_MCASP_AFSXCTL_VALUE, BELA_TLV_MCASP_ACLKXCTL_VALUE, BELA_TLV_MCASP_AHCLKXCTL_VALUE, BELA_TLV_MCASP_XTDM_VALUE, BELA_TLV_MCASP_XINTCTL_VALUE -MCASP_SET_TX_MULTI_TLV: +MCASP_SET_TX_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 BELA_MULTI_TLV_OR_JMP_TO MCASP_SET_TX_NOT_MULTI_TLV @@ -1469,10 +1464,10 @@ WRITE_FRAME_NOT_CTAG_FACE: WRITE_FRAME_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ #ifdef ENABLE_BELA_TLV32 - BELA_NOT_MULTI_TLV_OR_JMP_TO WRITE_FRAME_MULTI_TLV + IF_NOT_BELA_TLV32_JMP_TO WRITE_FRAME_NOT_BELA_TLV32 MCASP_WRITE_TO_DATAPORT 0x00, 4 MCASP_WRITE_TO_DATAPORT 0x00, 4 -WRITE_FRAME_MULTI_TLV: +WRITE_FRAME_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 BELA_MULTI_TLV_OR_JMP_TO WRITE_FRAME_NOT_MULTI_TLV From d9fcfe521e49e45c3ae4be7d5fc0405b7f5b5b29 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 30 Mar 2020 17:29:53 +0000 Subject: [PATCH 028/148] PRU: NOP Renamed macros for clarity --- pru/pru_rtaudio_irq.p | 55 ++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 3453a5973..9d0a05a59 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -477,12 +477,12 @@ SBBO r27, reg_comm_addr, COMM_ERROR_OCCURED, 4 MOV r31.b0, PRU_SYSTEM_EVENT_RTDM_WRITE_VALUE .endm -.macro BELA_MINI_OR_JMP_TO +.macro IF_NOT_BELA_MINI_JMP_TO .mparam DEST QBBC DEST, reg_flags, FLAG_BIT_BELA_MINI .endm -.macro BELA_MULTI_TLV_OR_JMP_TO +.macro IF_NOT_BELA_MULTI_TLV_JMP_TO .mparam DEST QBBC DEST, reg_flags, FLAG_BIT_BELA_MULTI_TLV .endm @@ -503,17 +503,17 @@ DONE: .endm #define IF_HAS_BELA_SPI_ADC_CS_JMP_TO IF_HAS_ANALOG_DAC_JMP_TO -.macro CTAG_OR_JMP_TO +.macro IF_NOT_CTAG_JMP_TO .mparam DEST QBBC DEST, reg_flags, FLAG_BIT_CTAG .endm -.macro CTAG_FACE_OR_JMP_TO +.macro IF_NOT_CTAG_FACE_JMP_TO .mparam DEST QBBC DEST, reg_flags, FLAG_BIT_CTAG_FACE .endm -.macro CTAG_BEAST_OR_JMP_TO +.macro IF_NOT_CTAG_BEAST_JMP_TO .mparam DEST QBBC DEST, reg_flags, FLAG_BIT_CTAG_BEAST .endm @@ -1319,13 +1319,13 @@ SPI_INIT_DONE: // set MCASP RX #ifdef ENABLE_CTAG_FACE - CTAG_FACE_OR_JMP_TO MCASP_SET_RX_NOT_CTAG_FACE + IF_NOT_CTAG_FACE_JMP_TO MCASP_SET_RX_NOT_CTAG_FACE MCASP_SET_RX CTAG_FACE_MCASP_DATA_FORMAT_RX_VALUE, CTAG_FACE_MCASP_AFSRCTL_VALUE, CTAG_FACE_MCASP_ACLKRCTL_VALUE, CTAG_FACE_MCASP_AHCLKRCTL_VALUE, CTAG_FACE_MCASP_RTDM_VALUE, CTAG_FACE_MCASP_RINTCTL_VALUE, MCASP_DATA_MASK QBA MCASP_SET_RX_DONE MCASP_SET_RX_NOT_CTAG_FACE: #endif /* ENABLE_CTAG_FACE */ #ifdef ENABLE_CTAG_BEAST - CTAG_BEAST_OR_JMP_TO MCASP_SET_RX_NOT_CTAG_BEAST + IF_NOT_CTAG_BEAST_JMP_TO MCASP_SET_RX_NOT_CTAG_BEAST MCASP_SET_RX CTAG_BEAST_MCASP_DATA_FORMAT_RX_VALUE, CTAG_BEAST_MCASP_AFSRCTL_VALUE, CTAG_BEAST_MCASP_ACLKRCTL_VALUE, CTAG_BEAST_MCASP_AHCLKRCTL_VALUE, CTAG_BEAST_MCASP_RTDM_VALUE, CTAG_BEAST_MCASP_RINTCTL_VALUE, MCASP_DATA_MASK QBA MCASP_SET_RX_DONE MCASP_SET_RX_NOT_CTAG_BEAST: @@ -1336,7 +1336,7 @@ MCASP_SET_RX_NOT_CTAG_BEAST: MCASP_SET_RX_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 - BELA_MULTI_TLV_OR_JMP_TO MCASP_SET_RX_NOT_MULTI_TLV + IF_NOT_BELA_MULTI_TLV_JMP_TO MCASP_SET_RX_NOT_MULTI_TLV // reg_flags should hold the number of active channels, up to // 32, in pairs (i.e. 0 --> 2, 1 --> 4, ..., 15 --> 32) @@ -1365,13 +1365,13 @@ MCASP_SET_RX_DONE: // set MCASP TX #ifdef ENABLE_CTAG_FACE - CTAG_FACE_OR_JMP_TO MCASP_SET_TX_NOT_CTAG_FACE + IF_NOT_CTAG_FACE_JMP_TO MCASP_SET_TX_NOT_CTAG_FACE MCASP_SET_TX CTAG_FACE_MCASP_DATA_FORMAT_TX_VALUE, CTAG_FACE_MCASP_AFSXCTL_VALUE, CTAG_FACE_MCASP_ACLKXCTL_VALUE, CTAG_FACE_MCASP_AHCLKXCTL_VALUE, CTAG_FACE_MCASP_XTDM_VALUE, CTAG_FACE_MCASP_XINTCTL_VALUE QBA MCASP_SET_TX_DONE MCASP_SET_TX_NOT_CTAG_FACE: #endif /* ENABLE_CTAG_FACE */ #ifdef ENABLE_CTAG_BEAST - CTAG_BEAST_OR_JMP_TO MCASP_SET_TX_NOT_CTAG_BEAST + IF_NOT_CTAG_BEAST_JMP_TO MCASP_SET_TX_NOT_CTAG_BEAST MCASP_SET_TX CTAG_BEAST_MCASP_DATA_FORMAT_TX_VALUE, CTAG_BEAST_MCASP_AFSXCTL_VALUE, CTAG_BEAST_MCASP_ACLKXCTL_VALUE, CTAG_BEAST_MCASP_AHCLKXCTL_VALUE, CTAG_BEAST_MCASP_XTDM_VALUE, CTAG_BEAST_MCASP_XINTCTL_VALUE QBA MCASP_SET_TX_DONE MCASP_SET_TX_NOT_CTAG_BEAST: @@ -1382,7 +1382,7 @@ MCASP_SET_TX_NOT_CTAG_BEAST: MCASP_SET_TX_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 - BELA_MULTI_TLV_OR_JMP_TO MCASP_SET_TX_NOT_MULTI_TLV + IF_NOT_BELA_MULTI_TLV_JMP_TO MCASP_SET_TX_NOT_MULTI_TLV // Calculate which TDM slots to activate LBBO r2, reg_comm_addr, COMM_ACTIVE_TDM_SLOTS, 4 // How many audio channels? @@ -1429,7 +1429,7 @@ MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 11) // Set XSMRST // Write a full frame to transmit FIFOs to prevent underflow and keep slots synced // Can be probably ignored if first underrun gets ignored for better performance => TODO: test #ifdef ENABLE_CTAG_FACE -CTAG_FACE_OR_JMP_TO WRITE_FRAME_NOT_CTAG_FACE +IF_NOT_CTAG_FACE_JMP_TO WRITE_FRAME_NOT_CTAG_FACE MCASP_WRITE_TO_DATAPORT 0x00, 4 MCASP_WRITE_TO_DATAPORT 0x00, 4 MCASP_WRITE_TO_DATAPORT 0x00, 4 @@ -1443,7 +1443,7 @@ CTAG_FACE_OR_JMP_TO WRITE_FRAME_NOT_CTAG_FACE WRITE_FRAME_NOT_CTAG_FACE: #endif /* ENABLE_CTAG_FACE */ #ifdef ENABLE_CTAG_BEAST - CTAG_BEAST_OR_JMP_TO WRITE_FRAME_NOT_CTAG_BEAST + IF_NOT_CTAG_BEAST_JMP_TO WRITE_FRAME_NOT_CTAG_BEAST MCASP_WRITE_TO_DATAPORT 0x00, 4 MCASP_WRITE_TO_DATAPORT 0x00, 4 MCASP_WRITE_TO_DATAPORT 0x00, 4 @@ -1470,7 +1470,7 @@ WRITE_FRAME_NOT_CTAG_BEAST: WRITE_FRAME_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 - BELA_MULTI_TLV_OR_JMP_TO WRITE_FRAME_NOT_MULTI_TLV + IF_NOT_BELA_MULTI_TLV_JMP_TO WRITE_FRAME_NOT_MULTI_TLV READ_MULTI_TLV_CHANNELS r2 // How many channels? WRITE_FRAME_MULTI_TLV_LOOP: MCASP_WRITE_TO_DATAPORT 0x00, 4 // Write 4 bytes for each channel @@ -1729,7 +1729,7 @@ MCASP_TX_ERROR_HANDLE_END: // Load audio frame from memory, store zeros in their place, and increment pointer to next frame #ifdef ENABLE_CTAG_FACE -CTAG_FACE_OR_JMP_TO LOAD_AUDIO_FRAME_NOT_CTAG_FACE +IF_NOT_CTAG_FACE_JMP_TO LOAD_AUDIO_FRAME_NOT_CTAG_FACE LBCO r0, C_MCASP_MEM, reg_mcasp_dac_current, 16 SBCO r8, C_MCASP_MEM, reg_mcasp_dac_current, 16 ADD reg_mcasp_dac_current, reg_mcasp_dac_current, 16 @@ -1737,7 +1737,7 @@ CTAG_FACE_OR_JMP_TO LOAD_AUDIO_FRAME_NOT_CTAG_FACE LOAD_AUDIO_FRAME_NOT_CTAG_FACE: #endif /* ENABLE_CTAG_FACE */ #ifdef ENABLE_CTAG_BEAST -CTAG_BEAST_OR_JMP_TO LOAD_AUDIO_FRAME_NOT_CTAG_BEAST +IF_NOT_CTAG_BEAST_JMP_TO LOAD_AUDIO_FRAME_NOT_CTAG_BEAST LBCO r0, C_MCASP_MEM, reg_mcasp_dac_current, 32 SBCO r8, C_MCASP_MEM, reg_mcasp_dac_current, 32 ADD reg_mcasp_dac_current, reg_mcasp_dac_current, 32 @@ -1753,7 +1753,7 @@ LOAD_AUDIO_FRAME_NOT_CTAG_BEAST: LOAD_AUDIO_FRAME_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 - BELA_MULTI_TLV_OR_JMP_TO LOAD_AUDIO_FRAME_NOT_MULTI_TLV + IF_NOT_BELA_MULTI_TLV_JMP_TO LOAD_AUDIO_FRAME_NOT_MULTI_TLV // Number of bytes to load depends on number of active TDM slots // LBCO/SBCO only support r0 as indicator of number of bytes // so load begins from r1 @@ -1781,7 +1781,7 @@ LOAD_AUDIO_FRAME_DONE: MOV r17, 0xFFFF #ifdef ENABLE_CTAG_FACE -CTAG_FACE_OR_JMP_TO WRITE_AUDIO_FRAME_NOT_CTAG_FACE +IF_NOT_CTAG_FACE_JMP_TO WRITE_AUDIO_FRAME_NOT_CTAG_FACE AND r8, r17, r0 LSR r9, r0, 16 AND r10, r17, r1 @@ -1795,7 +1795,7 @@ CTAG_FACE_OR_JMP_TO WRITE_AUDIO_FRAME_NOT_CTAG_FACE WRITE_AUDIO_FRAME_NOT_CTAG_FACE: #endif /* ENABLE_CTAG_FACE */ #ifdef ENABLE_CTAG_BEAST -CTAG_BEAST_OR_JMP_TO WRITE_AUDIO_FRAME_NOT_CTAG_BEAST +IF_NOT_CTAG_BEAST_JMP_TO WRITE_AUDIO_FRAME_NOT_CTAG_BEAST // Note: Could be optimized by only using single operation to write data to McASP FIFO, // but 24 registers need to be free for use AND r8, r17, r0 @@ -1828,7 +1828,7 @@ IF_NOT_BELA_TLV32_JMP_TO WRITE_AUDIO_FRAME_NOT_BELA_TLV32 WRITE_AUDIO_FRAME_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 -BELA_MULTI_TLV_OR_JMP_TO WRITE_AUDIO_FRAME_NOT_MULTI_TLV +IF_NOT_BELA_MULTI_TLV_JMP_TO WRITE_AUDIO_FRAME_NOT_MULTI_TLV AND r9, r17, r1 LSR r10, r1, 16 MCASP_WRITE_TO_DATAPORT r9, 8 @@ -1905,7 +1905,7 @@ MCASP_RX_INTR_RECEIVED: // mcasp_r_intr_pend MOV r17, 0xFFFF #ifdef ENABLE_CTAG_FACE - CTAG_FACE_OR_JMP_TO FRAME_READ_NOT_CTAG_FACE + IF_NOT_CTAG_FACE_JMP_TO FRAME_READ_NOT_CTAG_FACE MCASP_READ_FROM_DATAPORT r8, 32 AND r0, r8, r17 LSL r16, r9, 16 @@ -1932,7 +1932,7 @@ MCASP_RX_INTR_RECEIVED: // mcasp_r_intr_pend FRAME_READ_NOT_CTAG_FACE: #endif /* ENABLE_CTAG_FACE */ #ifdef ENABLE_CTAG_BEAST - CTAG_BEAST_OR_JMP_TO FRAME_READ_NOT_CTAG_BEAST + IF_NOT_CTAG_BEAST_JMP_TO FRAME_READ_NOT_CTAG_BEAST // Check if there is at least one full frame in FIFO. // This is only required for CTAG Beast MCASP_REG_READ_EXT MCASP_RFIFOSTS, r27 @@ -1994,10 +1994,7 @@ FRAME_READ_NOT_CTAG_BEAST: FRAME_READ_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 - BELA_MULTI_TLV_OR_JMP_TO FRAME_READ_NOT_MULTI_TLV - //QBA FRAME_READ_NOT_MULTI_TLV - - // END TLVTODO TESTING + IF_NOT_BELA_MULTI_TLV_JMP_TO FRAME_READ_NOT_MULTI_TLV READ_MULTI_TLV_CHANNELS r0 QBGT FRAME_READ_MULTI_TLV_LT16CHAN, r0, 16 @@ -2282,7 +2279,7 @@ NEXT_FRAME: CLR reg_flags, reg_flags, FLAG_BIT_MCASP_RX_PROCESSED #ifdef ENABLE_CTAG_FACE -CTAG_FACE_OR_JMP_TO SET_REG_FRAMES_NOT_CTAG_FACE +IF_NOT_CTAG_FACE_JMP_TO SET_REG_FRAMES_NOT_CTAG_FACE // Set reg frames total based on number of analog channels // 8 analog ch => LSR 1 // 4 analog ch => LSR 2 @@ -2305,7 +2302,7 @@ SET_REG_FRAMES_NOT_CTAG_FACE: #endif /* ENABLE_CTAG_FACE */ #ifdef ENABLE_CTAG_BEAST -CTAG_BEAST_OR_JMP_TO SET_REG_FRAMES_NOT_CTAG_BEAST +IF_NOT_CTAG_BEAST_JMP_TO SET_REG_FRAMES_NOT_CTAG_BEAST // Set reg frames total based on number of analog channels // 8 analog ch => LSR 2 // 4 analog ch => LSR 3 @@ -2346,7 +2343,7 @@ BELA_TLV32_ANALOG_CFG_END: SET_REG_FRAMES_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 -BELA_MULTI_TLV_OR_JMP_TO SET_REG_FRAMES_NOT_BELA_MULTI_TLV +IF_NOT_BELA_MULTI_TLV_JMP_TO SET_REG_FRAMES_NOT_BELA_MULTI_TLV // Set reg frames total based on number of analog channels // 8 analog ch => LSL 1 // 4 analog ch => no shifting From 2fb4bd12cacde602b62709d621216db29da7f425 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 30 Mar 2020 17:42:51 +0000 Subject: [PATCH 029/148] PRU: added QBA when done --- pru/pru_rtaudio_irq.p | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 9d0a05a59..39e109d25 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -1333,6 +1333,7 @@ MCASP_SET_RX_NOT_CTAG_BEAST: #ifdef ENABLE_BELA_TLV32 IF_NOT_BELA_TLV32_JMP_TO MCASP_SET_RX_NOT_BELA_TLV32 MCASP_SET_RX BELA_TLV_MCASP_DATA_FORMAT_RX_VALUE, BELA_TLV_MCASP_AFSRCTL_VALUE, BELA_TLV_MCASP_ACLKRCTL_VALUE, BELA_TLV_MCASP_AHCLKRCTL_VALUE, BELA_TLV_MCASP_RTDM_VALUE, BELA_TLV_MCASP_RINTCTL_VALUE, MCASP_DATA_MASK + QBA MCASP_SET_RX_DONE MCASP_SET_RX_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 @@ -1358,6 +1359,7 @@ MCASP_SET_RX_MULTI_TLV_NONZERO: OR r3, r3, 0x03 // Always activate the first two slots (failsafe) MCASP_SET_RX BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE, BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE, BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE, BELA_MULTI_TLV_MCASP_AHCLKRCTL_VALUE, r3, BELA_MULTI_TLV_MCASP_RINTCTL_VALUE, MCASP_DATA_MASK + QBA MCASP_SET_RX_DONE MCASP_SET_RX_NOT_MULTI_TLV: #endif /* ENABLE_BELA_MULTI_TLV32 */ @@ -1379,6 +1381,7 @@ MCASP_SET_TX_NOT_CTAG_BEAST: #ifdef ENABLE_BELA_TLV32 IF_NOT_BELA_TLV32_JMP_TO MCASP_SET_TX_NOT_BELA_TLV32 MCASP_SET_TX BELA_TLV_MCASP_DATA_FORMAT_TX_VALUE, BELA_TLV_MCASP_AFSXCTL_VALUE, BELA_TLV_MCASP_ACLKXCTL_VALUE, BELA_TLV_MCASP_AHCLKXCTL_VALUE, BELA_TLV_MCASP_XTDM_VALUE, BELA_TLV_MCASP_XINTCTL_VALUE + QBA MCASP_SET_TX_DONE MCASP_SET_TX_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 @@ -1392,6 +1395,7 @@ MCASP_SET_TX_NOT_BELA_TLV32: OR r3, r3, 0x03 // Always activate the first two slots (failsafe) MCASP_SET_TX BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE, BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE, BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE, BELA_MULTI_TLV_MCASP_AHCLKXCTL_VALUE, r3, BELA_MULTI_TLV_MCASP_XINTCTL_VALUE + QBA MCASP_SET_TX_DONE MCASP_SET_TX_NOT_MULTI_TLV: #endif /* ENABLE_BELA_MULTI_TLV32 */ MCASP_SET_TX_DONE: @@ -1825,6 +1829,7 @@ IF_NOT_BELA_TLV32_JMP_TO WRITE_AUDIO_FRAME_NOT_BELA_TLV32 AND r8, r17, r0 LSR r9, r0, 16 MCASP_WRITE_TO_DATAPORT r8, 8 + QBA WRITE_AUDIO_FRAME_DONE WRITE_AUDIO_FRAME_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 @@ -1870,6 +1875,7 @@ IF_NOT_BELA_MULTI_TLV_JMP_TO WRITE_AUDIO_FRAME_NOT_MULTI_TLV // (r0 * 2) >= 32 WRITE_AUDIO_FRAME_MULTI_TLV_DONE: + QBA WRITE_AUDIO_FRAME_DONE WRITE_AUDIO_FRAME_NOT_MULTI_TLV: #endif /* ENABLE_BELA_MULTI_TLV32 */ WRITE_AUDIO_FRAME_DONE: @@ -1991,6 +1997,7 @@ FRAME_READ_NOT_CTAG_BEAST: SBCO r0, C_MCASP_MEM, reg_mcasp_adc_current, 4 // store result ADD reg_mcasp_adc_current, reg_mcasp_adc_current, 4 // increment memory pointer + QBA FRAME_READ_DONE FRAME_READ_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 @@ -2052,7 +2059,8 @@ FRAME_READ_MULTI_TLV_LT16CHAN: FRAME_READ_MULTI_TLV_STORE: SBCO r1, C_MCASP_MEM, reg_mcasp_adc_current, b0 // store result ADD reg_mcasp_adc_current, reg_mcasp_adc_current, r0.b0 // increment memory pointer - + + QBA FRAME_READ_DONE FRAME_READ_NOT_MULTI_TLV: #endif /* ENABLE_BELA_MULTI_TLV32 */ From 610e129a072aa472a75f2cbad84eae71bc31a803 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 30 Mar 2020 20:26:38 +0000 Subject: [PATCH 030/148] PRU: one extra register filled with zeros for MULTI_TLV --- pru/pru_rtaudio_irq.p | 1 + 1 file changed, 1 insertion(+) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 39e109d25..51298dfeb 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -1730,6 +1730,7 @@ MCASP_TX_ERROR_HANDLE_END: LDI r13, 0 LDI r14, 0 LDI r15, 0 + LDI r16, 0 // Load audio frame from memory, store zeros in their place, and increment pointer to next frame #ifdef ENABLE_CTAG_FACE From 9883ed52b0f83f5940dabe0df1010583e585bda7 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 30 Mar 2020 21:07:49 +0000 Subject: [PATCH 031/148] PRU: NOP, cleaning up unused code --- pru/pru_rtaudio_irq.p | 113 +----------------------------------------- 1 file changed, 1 insertion(+), 112 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 51298dfeb..e85fd1008 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -1078,39 +1078,6 @@ START: // Configure PRU to receive external events: disable all MII_RT events PRU_ICSS_CFG_REG_WRITE_EXT CFG_REG_MII_RT, 0x0 -#ifdef AAA - // Set polarity of system events - PRU_ICSS_INTC_REG_WRITE_EXT INTC_REG_SIPR0, 0xFFFFFFFF - PRU_ICSS_INTC_REG_WRITE_EXT INTC_REG_SIPR1, 0xFFFFFFFF - - // Set type of system events - PRU_ICSS_INTC_REG_WRITE_EXT INTC_REG_SITR0, 0x00000000 - PRU_ICSS_INTC_REG_WRITE_EXT INTC_REG_SITR1, 0x00000000 - - // Map McASP0 (Tx / Rx) and McSPI0 interrupts to channel 0 - PRU_ICSS_INTC_REG_WRITE_EXT INTC_REG_CMR11, 0x00000000 - PRU_ICSS_INTC_REG_WRITE_EXT INTC_REG_CMR13, 0x00000000 - - // Map interrupt channel N to host interrupt N - PRU_ICSS_INTC_REG_WRITE_EXT INTC_REG_HMR0, 0x3020100 - PRU_ICSS_INTC_REG_WRITE_EXT INTC_REG_HMR1, 0x7060504 - PRU_ICSS_INTC_REG_WRITE_EXT INTC_REG_HMR2, 0x908 - - // Clear all system events (maybe safer to only clear system event 54 and 55) - PRU_ICSS_INTC_REG_WRITE_EXT INTC_REG_SECR0, 0xFFFFFFFF - PRU_ICSS_INTC_REG_WRITE_EXT INTC_REG_SECR1, 0xFFFFFFFF - - // Enable system events 44 (SINTERRUPTN), 54 (mcasp_r_intr_pend) and 55 (mcasp_x_intr_pend) - //PRU_ICSS_INTC_REG_WRITE_EXT INTC_REG_EISR, (0x00000000 | PRU_SYS_EV_MCSPI_INTR) - PRU_ICSS_INTC_REG_WRITE_EXT INTC_REG_EISR, (0x00000000 | PRU_SYS_EV_MCASP_RX_INTR) - PRU_ICSS_INTC_REG_WRITE_EXT INTC_REG_EISR, (0x00000000 | PRU_SYS_EV_MCASP_TX_INTR) - - // Enable all host interrupts (0/1: PRU, 2-9: ARM) - PRU_ICSS_INTC_REG_WRITE_EXT INTC_REG_HIER, 0x3FF - - // Globally enable all interrupts - PRU_ICSS_INTC_REG_WRITE_EXT INTC_REG_GER, 0x1 -#endif PRU_INTC_INIT_DONE: // Load useful registers for addressing SPI @@ -1175,18 +1142,6 @@ CTAG_BEAST_CHECK_DONE: LBBO r2, reg_comm_addr, COMM_USE_DIGITAL, 4 QBEQ DIGITAL_INIT_DONE, r2, 0 // if we use digital SET reg_flags, reg_flags, FLAG_BIT_USE_DIGITAL -/* This block of code is not really needed, as the memory is initialized by ARM before the PRU is started. -Will leave it here for future reference -DIGITAL_INIT: //set the digital buffer to 0x0000ffff (all inputs), to prevent unwanted high outputs - //the loop is unrolled by a factor of four just to take advantage of the speed of SBBO on larger byte bursts, but there is no real need for it - MOV r2, 0x0000ffff //value to store. 0x0000ffff means all inputs - MOV r3, MEM_DIGITAL_BASE //start of the digital buffer - MOV r4, MEM_DIGITAL_BASE+2*MEM_DIGITAL_BUFFER1_OFFSET //end of the digital buffer -DIGITAL_INIT_BUFFER_LOOP: - SBBO r2, r3, 0, 4 - ADD r3, r3, 4 //increment pointer - QBGT DIGITAL_INIT_BUFFER_LOOP, r3, r4 //loop until we reach the end of the buffer -*/ DIGITAL_INIT_DONE: // Check if we should use an external multiplexer capelet @@ -1505,72 +1460,6 @@ MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 12) // Set XFRST SET reg_flags, reg_flags, FLAG_BIT_MCSPI_FIRST_FOUR_CH MOV r2, 0 SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4 // Start with frame count of 0 -/* This block of code is not really needed, as the memory is initialized by ARM before the PRU is started. -Will leave it here for future reference -//Initialise all SPI and audio buffers (DAC0, DAC1, ADC0, ADC1) to zero. -//This is useful for analog outs so they do not have spikes during the first buffer. -//This is not very useful for audio, as you still hear the initial "tumpf" when the converter starts -//and each sample in the DAC buffer is reset to 0 after it is written to the DAC. - - QBBC SPI_INIT_BUFFER_DONE, reg_flags, FLAG_BIT_USE_SPI -//Initialize SPI buffers -//compute the memory offset of the end of the audio buffer and store it in r4 - SUB r4, reg_dac_buf1, reg_dac_buf0 // length of the buffer, assumes reg_dac_buf1>ref_dac_buf0 - LSL r4, r4, 2 //length of four buffers (DAC0, DAC1, ADC0, ADC1) - ADD r4, reg_dac_buf0, r4 //total offset - MOV r2, 0// value to store - MOV r3, 0 // offset counter -SPI_INIT_BUFFER_LOOP: - SBCO r2, C_ADC_DAC_MEM, r3, 4 - ADD r3, r3, 4 - QBGT SPI_INIT_BUFFER_LOOP, r3, r4 -SPI_INIT_BUFFER_DONE: - -//Initialize audio buffers -//compute the memory offset of the end of the audio buffer and store it in r4 - SUB r4, reg_mcasp_buf1, reg_mcasp_buf0 // length of the buffer, assumes reg_mcasp_buf1>ref_mcasp_buf0 - LSL r4, r4, 2 //length of four buffers (DAC0, DAC1, ADC0, ADC1) - ADD r4, reg_mcasp_buf0, r4 //total offset - MOV r2, 0 // value to store - MOV r3, 0 // offset counter - MCASP_INIT_BUFFER_LOOP: - SBCO r2, C_MCASP_MEM, r3, 4 - ADD r3, r3, 4 - QBGT MCASP_INIT_BUFFER_LOOP, r3, r4 -*/ - -/* -// Here we are out of sync by one TDM slot since the 0 word transmitted above will have occupied -// the first output slot. Send one more word before jumping into the loop. -#ifdef CTAG_FACE_8CH // commented -#error NOT IMPLEMENTED -// the 8 channel version is out of sync by 7 TDM slots. -// Using reg_dac_current as a temp register -MOV reg_dac_current, 7 -#endif -MCASP_DAC_WAIT_BEFORE_LOOP: - LBBO r2, reg_mcasp_addr, MCASP_XSTAT, 4 - QBBC MCASP_DAC_WAIT_BEFORE_LOOP, r2, MCASP_XSTAT_XDATA_BIT - - MCASP_WRITE_TO_DATAPORT 0x00 - -// Likewise, read and discard the first sample we get back from the ADC. This keeps the DAC and ADC -// in sync in terms of which TDM slot we are reading (empirically found that we should throw this away -// rather than keep it and invert the phase) - -MCASP_ADC_WAIT_BEFORE_LOOP: - LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4 - QBBC MCASP_ADC_WAIT_BEFORE_LOOP, r2, MCASP_RSTAT_RDATA_BIT - - MCASP_READ_FROM_DATAPORT r2 - -#ifdef CTAG_FACE_8CH // commented -#error NOT IMPLEMENTED - SUB reg_dac_current, reg_dac_current, 1 - QBNE MCASP_DAC_WAIT_BEFORE_LOOP, reg_dac_current, 0 -#endif -*/ - WRITE_ONE_BUFFER: @@ -1769,7 +1658,7 @@ LOAD_AUDIO_FRAME_NOT_BELA_TLV32: QBGT LOAD_AUDIO_FRAME_MULTI_TLV_LT16CHAN, r0, 16 LDI r0, 16 LOAD_AUDIO_FRAME_MULTI_TLV_LT16CHAN: - LSL r0, r0, 1 // 16 bits per channel + LSL r0, r0, 1 // 16 bits per channel LBCO r1, C_MCASP_MEM, reg_mcasp_dac_current, b0 SBCO r9, C_MCASP_MEM, reg_mcasp_dac_current, b0 ADD reg_mcasp_dac_current, reg_mcasp_dac_current, r0.b0 From dc8d4448ce35f661ad75365dcd7a55151d1f72af Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 30 Mar 2020 21:45:48 +0000 Subject: [PATCH 032/148] PRU: Adding offset of the first buffer to the second (it used to work because the first one was 0 --- pru/pru_rtaudio_irq.p | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index e85fd1008..7ad49f793 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -1448,10 +1448,12 @@ MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 12) // Set XFRST LBBO reg_frame_spi_total, reg_comm_addr, COMM_BUFFER_SPI_FRAMES, 4 // Total frame count for SPI MOV reg_dac_buf0, 0 // DAC buffer 0 start pointer LSL reg_dac_buf1, reg_frame_spi_total, 1 // DAC buffer 1 start pointer = N[ch]*2[bytes]*bufsize + ADD reg_dac_buf1, reg_dac_buf1, reg_dac_buf0 LMBD r2, reg_num_channels, 1 // Returns 1, 2 or 3 depending on the number of channels LSL reg_dac_buf1, reg_dac_buf1, r2 // Multiply by 2, 4 or 8 to get the N[ch] scaling above MOV reg_mcasp_buf0, REG_MCASP_BUF0_INIT // McASP DAC buffer 0 start pointer LSL reg_mcasp_buf1, reg_frame_mcasp_total, r2 // McASP DAC buffer 1 start pointer = 2[ch]*2[bytes]*(N/4)[samples/spi]*bufsize + ADD reg_mcasp_buf1, reg_mcasp_buf1, reg_mcasp_buf0 CLR reg_flags, reg_flags, FLAG_BIT_BUFFER1 // Bit 0 holds which buffer we are on SET reg_flags, reg_flags, FLAG_BIT_MCASP_TX_FIRST_FRAME // 0 = first half of frame period SET reg_flags, reg_flags, FLAG_BIT_MCASP_RX_FIRST_FRAME From ef9e71073d998f754fb0f8a1962dfd29488fd3ae Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 30 Mar 2020 21:50:35 +0000 Subject: [PATCH 033/148] PRU: fixed comments --- pru/pru_rtaudio_irq.p | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 7ad49f793..bb394ebe9 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -140,7 +140,7 @@ #define COMM_MUX_CONFIG 52 // Whether to use the mux capelet, and how many channels #define COMM_MUX_END_CHANNEL 56 // Which mux channel the last buffer ended on #define COMM_BUFFER_SPI_FRAMES 60 // How many frames per buffer for analog i/o -#define COMM_BOARD_FLAGS 64 // Flags for the board we are on (BOARD_FLAGS_... are defined in include/PruBoardFlags.h) +#define COMM_BOARD_FLAGS 64 // Flags for the board we are on (BOARD_FLAGS_... are defined in include/PruArmCommon.h) #define COMM_ERROR_OCCURED 68 // Signals the ARM CPU that an error happened #define COMM_ACTIVE_TDM_SLOTS 72 // How many TDM slots contain useful data @@ -335,8 +335,8 @@ #define CTAG_FACE_MCASP_ACLKXCTL_VALUE CTAG_MCASP_ACLKRCTL_VALUE #define CTAG_FACE_MCASP_AHCLKRCTL_VALUE MCASP_AHCLKRCTL_VALUE #define CTAG_FACE_MCASP_AHCLKXCTL_VALUE MCASP_AHCLKXCTL_VALUE -#define CTAG_FACE_MCASP_AFSRCTL_VALUE 0x410 // 8 Slot I2S, external clk, polarity (rising edge), single word -#define CTAG_FACE_MCASP_AFSXCTL_VALUE 0x410 // 8 Slot I2S, external clk, polarity (rising edge), single word +#define CTAG_FACE_MCASP_AFSRCTL_VALUE 0x410 // 8 Slot TDM, external fsclk, polarity (rising edge), single word +#define CTAG_FACE_MCASP_AFSXCTL_VALUE 0x410 // 8 Slot TDM, external fsclk, polarity (rising edge), single word #define CTAG_FACE_MCASP_RTDM_VALUE 0xFF // Enable TDM slots 0 to 7 #define CTAG_FACE_MCASP_XTDM_VALUE 0xFF // Enable TDM slots 0 to 7 #define CTAG_FACE_MCASP_RINTCTL_VALUE MCASP_RINTCTL_VALUE @@ -348,8 +348,8 @@ #define CTAG_BEAST_MCASP_ACLKXCTL_VALUE CTAG_MCASP_ACLKRCTL_VALUE #define CTAG_BEAST_MCASP_AHCLKRCTL_VALUE MCASP_AHCLKRCTL_VALUE #define CTAG_BEAST_MCASP_AHCLKXCTL_VALUE MCASP_AHCLKXCTL_VALUE -#define CTAG_BEAST_MCASP_AFSRCTL_VALUE 0x810 // 16 Slot I2S, external clk, polarity (rising edge), single word -#define CTAG_BEAST_MCASP_AFSXCTL_VALUE 0x810 // 16 Slot I2S, external clk, polarity (rising edge), single word +#define CTAG_BEAST_MCASP_AFSRCTL_VALUE 0x810 // 16 Slot TDM, external fsclk, polarity (rising edge), single word +#define CTAG_BEAST_MCASP_AFSXCTL_VALUE 0x810 // 16 Slot TDM, external fsclk, polarity (rising edge), single word #define CTAG_BEAST_MCASP_RTDM_VALUE 0xFFFF // Enable TDM slots 0 to 15 #define CTAG_BEAST_MCASP_XTDM_VALUE 0xFFFF // Enable TDM slots 0 to 15 #define CTAG_BEAST_MCASP_RINTCTL_VALUE MCASP_RINTCTL_VALUE @@ -361,8 +361,8 @@ #define BELA_TLV_MCASP_ACLKXCTL_VALUE 0x00 // External clk, polarity (falling edge) #define BELA_TLV_MCASP_AHCLKRCTL_VALUE MCASP_AHCLKRCTL_VALUE #define BELA_TLV_MCASP_AHCLKXCTL_VALUE MCASP_AHCLKXCTL_VALUE -#define BELA_TLV_MCASP_AFSRCTL_VALUE 0x100 // 2 Slot I2S, external clk, polarity (rising edge), single bit -#define BELA_TLV_MCASP_AFSXCTL_VALUE 0x100 // 2 Slot I2S, external clk, polarity (rising edge), single bit +#define BELA_TLV_MCASP_AFSRCTL_VALUE 0x100 // 2 Slot I2S, external fsclk, polarity (rising edge), single bit +#define BELA_TLV_MCASP_AFSXCTL_VALUE 0x100 // 2 Slot I2S, external fsclk, polarity (rising edge), single bit #define BELA_TLV_MCASP_RTDM_VALUE 0x3 // Enable TDM slots 0 and 1 #define BELA_TLV_MCASP_XTDM_VALUE 0x3 // Enable TDM slots 0 and 1 #define BELA_TLV_MCASP_RINTCTL_VALUE MCASP_RINTCTL_VALUE @@ -370,19 +370,19 @@ // Values below are for 16x 16-bit TDM slots -#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits +#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits #define BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE 0x00 // External clk, polarity (falling edge) #define BELA_MULTI_TLV_MCASP_AHCLKRCTL_VALUE MCASP_AHCLKRCTL_VALUE #define BELA_MULTI_TLV_MCASP_AHCLKXCTL_VALUE MCASP_AHCLKXCTL_VALUE -#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits +#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits #define BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE 0x00 // External clk, polarity (falling edge) #ifdef CODEC_WCLK_MASTER -#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x800 // 16-slot TDM input, rising edge means beginning of frame -#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x800 // 16-slot TDM input, rising edge means beginning of frame +#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x800 // 16-slot TDM external fsclk, rising edge means beginning of frame +#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x800 // 16-slot TDM external fsclk, rising edge means beginning of frame #else -#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x802 // 16-slot TDM output, rising edge means beginning of frame -#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x802 // 16-slot TDM output, rising edge means beginning of frame +#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x802 // 16-slot TDM internal fsclk, rising edge means beginning of frame +#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x802 // 16-slot TDM internal fsclk, rising edge means beginning of frame #endif // RTDM and XTDM are calculated dynamically From aeef1d327d6819bab052e7f541e33f05c6a3301a Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 31 Mar 2020 01:15:32 +0000 Subject: [PATCH 034/148] PRU: reg_frame_mcasp_total now makes some sense (at least for MULTI_TLV), also removing the need for the CTAG_HALF_AS_MANY_INPUTS macro. Channels are now stored in the flags as plain channel count numbers, separately for inputs and outputs. Some refactoring. --- core/PRU.cpp | 5 +- pru/pru_rtaudio_irq.p | 198 +++++++++++++++++++++++++----------------- 2 files changed, 120 insertions(+), 83 deletions(-) diff --git a/core/PRU.cpp b/core/PRU.cpp index 691bb74ba..44bfc6cb6 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -613,15 +613,14 @@ void PRU::initialisePruCommon() else pruFrames = context->audioFrames / 2; // PRU assumes 8 "fake" channels when SPI is disabled pru_buffer_comm[PRU_BUFFER_SPI_FRAMES] = pruFrames; - pruBufferMcaspFrames = pruFrames * context->audioOutChannels / 2; - // TODO: it seems that PRU_BUFFER_MCASP_FRAMES is not very meaningful(cf pru_rtaudio_irq.p) + pruBufferMcaspFrames = context->audioFrames; pru_buffer_comm[PRU_BUFFER_MCASP_FRAMES] = pruBufferMcaspFrames; pru_buffer_comm[PRU_SHOULD_SYNC] = 0; pru_buffer_comm[PRU_SYNC_ADDRESS] = 0; pru_buffer_comm[PRU_SYNC_PIN_MASK] = 0; pru_buffer_comm[PRU_PRU_NUMBER] = pru_number; pru_buffer_comm[PRU_ERROR_OCCURRED] = 0; - pru_buffer_comm[PRU_ACTIVE_TDM_SLOTS] = context->audioOutChannels; + pru_buffer_comm[PRU_ACTIVE_TDM_SLOTS] = ((uint16_t)context->audioOutChannels & 0xFFFF) << 16 | ((uint16_t)(context->audioInChannels) & 0xFFFF); /* Set up multiplexer info */ if(context->multiplexerChannels == 2) { diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index bb394ebe9..1abb87c2e 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -20,7 +20,6 @@ // See https://github.com/BelaPlatform/Bela/issues/480 #define CTAG_IGNORE_UNUSED_INPUT_TDM_SLOTS -//#define MCASP_INPUTS_ARE_HALF_AS_MANY_AS_OUTPUTS // TODO: make it runtime (should not be there for BELA_TLV) #undef CODEC_WCLK_MASTER // Match this with I2c_MultiTLVCodec.cpp @@ -410,10 +409,20 @@ #define FLAG_BIT_CTAG_BEAST 13 #define FLAG_BIT_BELA_MULTI_TLV 14 -#define FLAG_BIT_AUDIO_CHANNELS0 16 -#define FLAG_BIT_AUDIO_CHANNELS1 17 -#define FLAG_BIT_AUDIO_CHANNELS2 18 -#define FLAG_BIT_AUDIO_CHANNELS3 19 +// reg_flags should hold the number of audio in/out channels, up to 32 +#define FLAG_BIT_AUDIO_IN_CHANNELS0 16 +#define FLAG_BIT_AUDIO_IN_CHANNELS1 17 +#define FLAG_BIT_AUDIO_IN_CHANNELS2 18 +#define FLAG_BIT_AUDIO_IN_CHANNELS3 19 +#define FLAG_BIT_AUDIO_IN_CHANNELS4 20 +#define FLAG_BIT_AUDIO_IN_CHANNELS5 21 + +#define FLAG_BIT_AUDIO_OUT_CHANNELS0 22 +#define FLAG_BIT_AUDIO_OUT_CHANNELS1 23 +#define FLAG_BIT_AUDIO_OUT_CHANNELS2 24 +#define FLAG_BIT_AUDIO_OUT_CHANNELS3 25 +#define FLAG_BIT_AUDIO_OUT_CHANNELS4 26 +#define FLAG_BIT_AUDIO_OUT_CHANNELS5 27 // Registers used throughout @@ -570,14 +579,82 @@ SETINPUT: //if it is an input, set the relevant bit DONE: .endm +.macro READ_ACTIVE_TDM_SLOTS_INTO_FLAGS + LBBO r27, reg_comm_addr, COMM_ACTIVE_TDM_SLOTS, 4 + // the high word contains the number of outputs + LSR r28, r27, 16 + LSL r28, r28, FLAG_BIT_AUDIO_OUT_CHANNELS0 + OR reg_flags, reg_flags, r28 + // the low word contains the number of inputs + MOV r28, 0xFFFF + AND r28, r27, r28 + LSL r28, r28, FLAG_BIT_AUDIO_IN_CHANNELS0 + OR reg_flags, reg_flags, r28 +.endm + // Read the number of audio channels from the flags register -// 4 bits indicate pairs of channels (i.e. 2 to 32) -.macro READ_MULTI_TLV_CHANNELS +.macro GET_NUM_AUDIO_IN_CHANNELS .mparam DEST - LSR DEST, reg_flags, FLAG_BIT_AUDIO_CHANNELS0 - AND DEST, DEST, 0x0F - ADD DEST, DEST, 1 - LSL DEST, DEST, 1 + LSR DEST, reg_flags, FLAG_BIT_AUDIO_IN_CHANNELS0 + AND DEST, DEST, (64-1) +.endm + +.macro GET_NUM_AUDIO_OUT_CHANNELS +.mparam DEST + LSR DEST, reg_flags, FLAG_BIT_AUDIO_OUT_CHANNELS0 + AND DEST, DEST, (64-1) +.endm + +.macro COMPUTE_TDM_MASK +.mparam reg_io + QBEQ DONE, reg_io, 0 + MOV r27, 0x1 // mask = (1 << numchannels) - 1 + LSL r27, r27, reg_io + SUB reg_io, r27, 1 +DONE: +.endm + +// reg_io should contain number of channels when the macro is called, and will +// contain the output value by the end +.macro COMPUTE_SIZE_OF_BUFFER +.mparam reg_io, reg_total_frames + // if there are 0 channels, return immediately (reg_io will already contain 0!) + QBEQ DONE, reg_io, 0 + LSL r27, reg_total_frames, 1 // r27 = 2[bytes]*n[frames] + MOV r28, reg_io + // from now on reg_io contains the output value + MOV reg_io, 0 +SIZE_LOOP: // compute r27 * N[ch] + ADD reg_io, reg_io, r27 + SUB r28, r28, 1 + QBNE SIZE_LOOP, r28, 0 + // now reg_out = N[ch]*2[bytes]*n[frames] +DONE: +.endm + +.macro COMPUTE_SIZE_OF_MCASP_DAC_BUFFER +.mparam reg_out + // The memory needed for one McASP DAC buffer is N[ch]*2[bytes]*n[frames] + GET_NUM_AUDIO_OUT_CHANNELS reg_out + COMPUTE_SIZE_OF_BUFFER reg_out, reg_frame_mcasp_total +.endm + +// this can only be used after reg_mcasp_buf0 and reg_mcasp_buf1 have been initialized +.macro COMPUTE_SIZE_OF_MCASP_DAC_BUFFER_FAST +.mparam reg_out + QBGT GREATER, reg_mcasp_buf1, reg_mcasp_buf0 + SUB reg_out, reg_mcasp_buf1, reg_mcasp_buf0 + QBA DONE +GREATER: + SUB reg_out, reg_mcasp_buf0, reg_mcasp_buf1 +DONE: +.endm + +.macro COMPUTE_SIZE_OF_MCASP_ADC_BUFFER +.mparam reg_out + // The memory needed for one McASP DAC buffer is N[ch]*2[bytes]*n[frames] + GET_NUM_AUDIO_IN_CHANNELS reg_out + COMPUTE_SIZE_OF_BUFFER reg_out, reg_frame_mcasp_total .endm QBA START_INTERMEDIATE // when first starting, go to START, skipping this section. @@ -1293,26 +1370,18 @@ MCASP_SET_RX_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 IF_NOT_BELA_MULTI_TLV_JMP_TO MCASP_SET_RX_NOT_MULTI_TLV - - // reg_flags should hold the number of active channels, up to - // 32, in pairs (i.e. 0 --> 2, 1 --> 4, ..., 15 --> 32) - LBBO r2, reg_comm_addr, COMM_ACTIVE_TDM_SLOTS, 4 // How many audio channels? - - QBNE MCASP_SET_RX_MULTI_TLV_NONZERO, r2, 0 - LDI r2, 2 // Sanity check: empty value defaults to stereo -MCASP_SET_RX_MULTI_TLV_NONZERO: - LSR r3, r2, 1 - SUB r3, r3, 1 // r3 = (r3 / 2) - 1 - AND r3, r3, 0x0F // mask out high bits (sanity check) - LSL r3, r3, FLAG_BIT_AUDIO_CHANNELS0 // shift to the right bit offset - OR reg_flags, reg_flags, r3 // this works because we know these bits are 0 in reg_flags before now - - // Calculate which TDM slots to activate - MOV r3, 0x1 // mask = (1 << numchannels) - 1 - LSL r3, r3, r2 - SUB r3, r3, 1 - OR r3, r3, 0x03 // Always activate the first two slots (failsafe) + READ_ACTIVE_TDM_SLOTS_INTO_FLAGS + GET_NUM_AUDIO_IN_CHANNELS r2 + GET_NUM_AUDIO_OUT_CHANNELS r3 + QBNE CHANNEL_COUNT_NOT_ZERO, r2, 0 + QBNE CHANNEL_COUNT_NOT_ZERO, r3, 0 + SEND_ERROR_TO_ARM ARM_ERROR_INVALID_INIT + HALT +CHANNEL_COUNT_NOT_ZERO: + + GET_NUM_AUDIO_IN_CHANNELS r3 + COMPUTE_TDM_MASK r3 MCASP_SET_RX BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE, BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE, BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE, BELA_MULTI_TLV_MCASP_AHCLKRCTL_VALUE, r3, BELA_MULTI_TLV_MCASP_RINTCTL_VALUE, MCASP_DATA_MASK QBA MCASP_SET_RX_DONE MCASP_SET_RX_NOT_MULTI_TLV: @@ -1341,13 +1410,8 @@ MCASP_SET_TX_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 IF_NOT_BELA_MULTI_TLV_JMP_TO MCASP_SET_TX_NOT_MULTI_TLV - - // Calculate which TDM slots to activate - LBBO r2, reg_comm_addr, COMM_ACTIVE_TDM_SLOTS, 4 // How many audio channels? - MOV r3, 0x1 // mask = (1 << numchannels) - 1 - LSL r3, r3, r2 - SUB r3, r3, 1 - OR r3, r3, 0x03 // Always activate the first two slots (failsafe) + GET_NUM_AUDIO_OUT_CHANNELS r3 + COMPUTE_TDM_MASK r3 MCASP_SET_TX BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE, BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE, BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE, BELA_MULTI_TLV_MCASP_AHCLKXCTL_VALUE, r3, BELA_MULTI_TLV_MCASP_XINTCTL_VALUE QBA MCASP_SET_TX_DONE @@ -1430,7 +1494,7 @@ WRITE_FRAME_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 IF_NOT_BELA_MULTI_TLV_JMP_TO WRITE_FRAME_NOT_MULTI_TLV - READ_MULTI_TLV_CHANNELS r2 // How many channels? + GET_NUM_AUDIO_OUT_CHANNELS r2 // How many channels? WRITE_FRAME_MULTI_TLV_LOOP: MCASP_WRITE_TO_DATAPORT 0x00, 4 // Write 4 bytes for each channel SUB r2, r2, 1 @@ -1451,9 +1515,9 @@ MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 12) // Set XFRST ADD reg_dac_buf1, reg_dac_buf1, reg_dac_buf0 LMBD r2, reg_num_channels, 1 // Returns 1, 2 or 3 depending on the number of channels LSL reg_dac_buf1, reg_dac_buf1, r2 // Multiply by 2, 4 or 8 to get the N[ch] scaling above - MOV reg_mcasp_buf0, REG_MCASP_BUF0_INIT // McASP DAC buffer 0 start pointer - LSL reg_mcasp_buf1, reg_frame_mcasp_total, r2 // McASP DAC buffer 1 start pointer = 2[ch]*2[bytes]*(N/4)[samples/spi]*bufsize - ADD reg_mcasp_buf1, reg_mcasp_buf1, reg_mcasp_buf0 + MOV reg_mcasp_buf0, REG_MCASP_BUF0_INIT // McASP DAC buffer 0 start pointer + COMPUTE_SIZE_OF_MCASP_DAC_BUFFER r2 + ADD reg_mcasp_buf1, r2, reg_mcasp_buf0 CLR reg_flags, reg_flags, FLAG_BIT_BUFFER1 // Bit 0 holds which buffer we are on SET reg_flags, reg_flags, FLAG_BIT_MCASP_TX_FIRST_FRAME // 0 = first half of frame period SET reg_flags, reg_flags, FLAG_BIT_MCASP_RX_FIRST_FRAME @@ -1479,34 +1543,22 @@ BELA_CHANNELS: ADD reg_adc_current, reg_adc_current, reg_dac_current // ADC: starts N * 2 * 2 * bufsize beyond DAC CHANNELS_DONE: MOV reg_mcasp_dac_current, reg_mcasp_buf0 // McASP: set current DAC pointer - // the CTAGs only use half as many input channels as there are outputs, so divide by 2 (LSR by 1) when computing offsets - // if I/O buffers are the same size, then McASP ADC: starts (N/2)*2bytes*bufsize beyond DAC - // otherwise: - // McASP ADC: starts - // 2bytes*nDacChannels*nDacFrames*2dacBuffers - // beyond DAC0 buffer - // or McASP ADC: starts - // 2bytes*nDacChannels*nDacFrames*1dacBuffer + - // + 2bytes*nAdcChannels+nAdcFrames*1adcBuffer - // beyond DAC1 buffer - // TODO: it seems that reg_frame_mcasp_total is not very meaningful(cf PRU.cpp) - LSL reg_mcasp_adc_current, reg_frame_mcasp_total, r2 -#ifdef MCASP_INPUTS_ARE_HALF_AS_MANY_AS_OUTPUTS + // If we are on the first buffer, mcasp_adc_current starts + // MCASP_DAC_BUFFER_SIZE*2 after reg_mcasp_dac_current + // If we are on the second buffer, mcasp_adc_current starts + // MCASP_DAC_BUFFER_SIZE + MCASP_ADC_BUFFER_SIZE after reg_mcasp_dac_current + COMPUTE_SIZE_OF_MCASP_DAC_BUFFER_FAST r2 + ADD reg_mcasp_adc_current, reg_mcasp_dac_current, r2 // add one DAC_BLK_SIZE QBNE MCASP_IS_ON_BUF1, reg_mcasp_buf0, REG_MCASP_BUF0_INIT - LSL reg_mcasp_adc_current, reg_mcasp_adc_current, 1 + ADD reg_mcasp_adc_current, reg_mcasp_adc_current, r2 // add another DAC_BLK_SIZE QBA MCASP_IS_ON_BUF_DONE MCASP_IS_ON_BUF1: - // r2 = reg_mcasp_adc_current * 1.5 - LSR r2, reg_mcasp_adc_current, 1 - ADD reg_mcasp_adc_current, reg_mcasp_adc_current, r2 + COMPUTE_SIZE_OF_MCASP_ADC_BUFFER r2 + ADD reg_mcasp_adc_current, reg_mcasp_adc_current, r2 // add one ADC_BLK_SIZE MCASP_IS_ON_BUF_DONE: -#else /* MCASP_INPUTS_ARE_HALF_AS_MANY_AS_OUTPUTS */ - LSL reg_mcasp_adc_current, reg_mcasp_adc_current, 1 -#endif /* MCASP_INPUTS_ARE_HALF_AS_MANY_AS_OUTPUTS */ - ADC reg_mcasp_adc_current, reg_mcasp_adc_current, reg_mcasp_dac_current MOV reg_frame_current, 0 QBBS DIGITAL_BASE_CHECK_SET, reg_flags, FLAG_BIT_BUFFER1 //check which buffer we are using for DIGITAL - // if we are here, we are using buffer0 + // if we are here, we are using buffer0 MOV reg_digital_current, MEM_DIGITAL_BASE QBA DIGITAL_BASE_CHECK_DONE DIGITAL_BASE_CHECK_SET: //if we are here, we are using buffer1 @@ -1656,7 +1708,7 @@ LOAD_AUDIO_FRAME_NOT_BELA_TLV32: LDI r16, 0 // TLVTODO: this only works up to 16 channels based on number of registers - READ_MULTI_TLV_CHANNELS r0 + GET_NUM_AUDIO_OUT_CHANNELS r0 QBGT LOAD_AUDIO_FRAME_MULTI_TLV_LT16CHAN, r0, 16 LDI r0, 16 LOAD_AUDIO_FRAME_MULTI_TLV_LT16CHAN: @@ -1895,7 +1947,7 @@ FRAME_READ_NOT_BELA_TLV32: #ifdef ENABLE_BELA_MULTI_TLV32 IF_NOT_BELA_MULTI_TLV_JMP_TO FRAME_READ_NOT_MULTI_TLV - READ_MULTI_TLV_CHANNELS r0 + GET_NUM_AUDIO_IN_CHANNELS r0 QBGT FRAME_READ_MULTI_TLV_LT16CHAN, r0, 16 LDI r0, 16 FRAME_READ_MULTI_TLV_LT16CHAN: @@ -2244,21 +2296,7 @@ SET_REG_FRAMES_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 IF_NOT_BELA_MULTI_TLV_JMP_TO SET_REG_FRAMES_NOT_BELA_MULTI_TLV - // Set reg frames total based on number of analog channels - // 8 analog ch => LSL 1 - // 4 analog ch => no shifting - // 2 analog ch => LSR 1 - QBEQ BELA_MULTI_TLV_ANALOG_8, reg_num_channels, 0x8 - QBEQ BELA_MULTI_TLV_ANALOG_CFG_END, reg_num_channels, 0x4 - QBEQ BELA_MULTI_TLV_ANALOG_2, reg_num_channels, 0x2 - -BELA_MULTI_TLV_ANALOG_8: // Eight channels - LSL r14, reg_frame_spi_total, 1 - JMP BELA_MULTI_TLV_ANALOG_CFG_END -BELA_MULTI_TLV_ANALOG_2: // Two channels - LSR r14, reg_frame_spi_total, 1 - -BELA_MULTI_TLV_ANALOG_CFG_END: + MOV r14, reg_frame_mcasp_total QBA SET_REG_FRAMES_DONE SET_REG_FRAMES_NOT_BELA_MULTI_TLV: #endif /* ENABLE_BELA_MULTI_TLV32 */ From 834299ac885a9c91b794e7c11abab6409d1f6291 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Wed, 1 Apr 2020 09:57:22 +0000 Subject: [PATCH 035/148] Makefile: when using RUN_WITH_PRU_BIN=true, use pru_rtaudio_irq.bin and generated the .txt files while building it --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index fc20f6609..a1513990d 100644 --- a/Makefile +++ b/Makefile @@ -87,8 +87,9 @@ ifeq ($(RUN_WITH_PRU_BIN),true) ifndef PROJECT $(warning PROJECT is not defined, so RUN_WITH_PRU_BIN will be ignored) endif # ifndef PROJECT -COMMAND_LINE_OPTIONS := --pru-file $(BASE_DIR)/pru_rtaudio.bin $(COMMAND_LINE_OPTIONS) +COMMAND_LINE_OPTIONS := --pru-file $(BASE_DIR)/pru_rtaudio_irq.bin $(COMMAND_LINE_OPTIONS) run: pru_rtaudio.bin +run: pru_rtaudio_irq.bin else build/core/PruBinary.o: build/pru/pru_rtaudio_bin.h build/pru/pru_rtaudio_irq_bin.h endif #ifeq($(RUN_WITH_PRU_BIN),true) @@ -463,7 +464,7 @@ endif %.bin: pru/%.p ifeq (,$(SYNTAX_FLAG)) $(AT) echo 'Building $<...' - $(AT) pasm -V2 -b "$<" > /dev/null + $(AT) pasm -V2 -L -c -b "$<" > /dev/null $(AT) echo ' ...done' endif $(AT) echo ' ' From c65e9fa1c8f7035d74d79f0931c4817e21b9a8ba Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Wed, 1 Apr 2020 15:58:29 +0000 Subject: [PATCH 036/148] PRU: all types of boards use the same method for loading I/O channels. --- pru/pru_rtaudio_irq.p | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 1abb87c2e..c9ab53ae1 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -1349,6 +1349,17 @@ SPI_INIT_DONE: MCASP_REG_WRITE MCASP_DITCTL, 0x00 MCASP_REG_WRITE MCASP_RMASK, MCASP_DATA_MASK // 16 bit data receive + // Check how many channels we have + READ_ACTIVE_TDM_SLOTS_INTO_FLAGS + GET_NUM_AUDIO_IN_CHANNELS r2 + GET_NUM_AUDIO_OUT_CHANNELS r3 + // And that they are a valid number + QBNE CHANNEL_COUNT_NOT_ZERO, r2, 0 + QBNE CHANNEL_COUNT_NOT_ZERO, r3, 0 + SEND_ERROR_TO_ARM ARM_ERROR_INVALID_INIT + HALT +CHANNEL_COUNT_NOT_ZERO: + // set MCASP RX #ifdef ENABLE_CTAG_FACE IF_NOT_CTAG_FACE_JMP_TO MCASP_SET_RX_NOT_CTAG_FACE @@ -1370,16 +1381,6 @@ MCASP_SET_RX_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ #ifdef ENABLE_BELA_MULTI_TLV32 IF_NOT_BELA_MULTI_TLV_JMP_TO MCASP_SET_RX_NOT_MULTI_TLV - - READ_ACTIVE_TDM_SLOTS_INTO_FLAGS - GET_NUM_AUDIO_IN_CHANNELS r2 - GET_NUM_AUDIO_OUT_CHANNELS r3 - QBNE CHANNEL_COUNT_NOT_ZERO, r2, 0 - QBNE CHANNEL_COUNT_NOT_ZERO, r3, 0 - SEND_ERROR_TO_ARM ARM_ERROR_INVALID_INIT - HALT -CHANNEL_COUNT_NOT_ZERO: - GET_NUM_AUDIO_IN_CHANNELS r3 COMPUTE_TDM_MASK r3 MCASP_SET_RX BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE, BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE, BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE, BELA_MULTI_TLV_MCASP_AHCLKRCTL_VALUE, r3, BELA_MULTI_TLV_MCASP_RINTCTL_VALUE, MCASP_DATA_MASK From d6264e71790e91b63f690d31aa927fd382d1c91d Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Wed, 1 Apr 2020 16:00:36 +0000 Subject: [PATCH 037/148] PRU: Bela/BelaMini should now work with pru_rtraudio_irq.p (assuming you : define CODEC_WCLK_MASTER and force to use this PRU code in PRU.cpp --- pru/pru_rtaudio_irq.p | 55 +++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index c9ab53ae1..6fd0db505 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -1528,6 +1528,44 @@ MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 12) // Set XFRST MOV r2, 0 SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4 // Start with frame count of 0 +#ifdef ATTEMPT_TO_RESYNC_BELA_ADC +// for BELA_TLV32, the left and right channels are swapped, so that each frame contains: +//R[n-1], L[n]. +//something similar was happening in pru_rtaudio.p and the trick was to wait for +//one sample to come in and then discard it +//we try two approaches here, one based on the same solution as there, and one based on a hack, but none of them seems to work. + +//perform a write to avoid a TX underrun. This is just for testing, remove it +//later, as it would be adding latency and possibly causing offset of the +//outputs + MCASP_WRITE_TO_DATAPORT r8, 32 + // temporarily enable writes through the CFG port (if not already enabled) + // (note: datasheet does not say that changing this after the McASP has + // started would work, but it seems that it does) + MOV r2, BELA_TLV_MCASP_DATA_FORMAT_TX_VALUE // TODO: get this value by reading the register + MOV r3, r2 // back up the value + SET r2.t3 // set it to read from CFG port + MCASP_REG_WRITE MCASP_RFMT, r2 // Set data format +#ifdef ATTEMPT_TO_RESYNC_BELA_ADC_OLD_STYLE +MCASP_ADC_WAIT_BEFORE_LOOP: + LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4 + QBBC MCASP_ADC_WAIT_BEFORE_LOOP, r2, MCASP_RSTAT_RDATA_BIT + MCASP_REG_READ_EXT MCASP_RBUF, r2 // actually read and discard the value +#endif // ATTEMPT_TO_RESYNC_BELA_ADC_OLD_STYLE +#ifdef ATTEMPT_TO_RESYNC_BELA_ADC_HACK +/// wait for an actual non-zero value. Hopefully this would mean that one valid +// sample has been received from the codec + MOV r4, 0 +LOOPTHIS: + MCASP_REG_READ_EXT MCASP_RBUF, r2 // actually read and discard the value + QBNE DONELOOPTHIS, r2, 0 + ADD r4, r4, 1 + QBA LOOPTHIS +DONELOOPTHIS: +#endif // ATTEMPT_TO_RESYNC_BELA_ADC_HACK + MCASP_REG_WRITE MCASP_RFMT, r3 // Restore original value +#endif // ATTEMPT_TO_RESYNC_BELA_ADC + WRITE_ONE_BUFFER: // Write a single buffer of DAC samples and read a buffer of ADC samples @@ -1935,7 +1973,7 @@ FRAME_READ_NOT_CTAG_BEAST: #ifdef ENABLE_BELA_TLV32 IF_NOT_BELA_TLV32_JMP_TO FRAME_READ_NOT_BELA_TLV32 - MCASP_READ_FROM_DATAPORT r8, 32 + MCASP_READ_FROM_DATAPORT r8, 8 AND r0, r8, r17 LSL r16, r9, 16 OR r0, r0, r16 @@ -2278,20 +2316,7 @@ SET_REG_FRAMES_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ #ifdef ENABLE_BELA_TLV32 IF_NOT_BELA_TLV32_JMP_TO SET_REG_FRAMES_NOT_BELA_TLV32 - // Set reg frames total based on number of analog channels - // 8 analog ch => LSL 1 - // 4 analog ch => no shifting - // 2 analog ch => LSR 1 - QBEQ BELA_TLV32_ANALOG_8, reg_num_channels, 0x8 - QBEQ BELA_TLV32_ANALOG_CFG_END, reg_num_channels, 0x4 - QBEQ BELA_TLV32_ANALOG_2, reg_num_channels, 0x2 - -BELA_TLV32_ANALOG_8: // Eight channels - LSL r14, reg_frame_mcasp_total, 1 - JMP BELA_TLV32_ANALOG_CFG_END -BELA_TLV32_ANALOG_2: // Two channels - LSR r14, reg_frame_mcasp_total, 1 -BELA_TLV32_ANALOG_CFG_END: + MOV r14, reg_frame_mcasp_total QBA SET_REG_FRAMES_DONE SET_REG_FRAMES_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ From 153e8ab64ede02bf3f78cad0c650be1e699642f9 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Wed, 1 Apr 2020 16:24:10 +0000 Subject: [PATCH 038/148] core: verbose logging of pru code in use --- core/PRU.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/PRU.cpp b/core/PRU.cpp index 44bfc6cb6..1760ca861 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -699,6 +699,9 @@ int PRU::start(char * const filename) return 1; } + if(gRTAudioVerbose) + printf("%ssing McASP->PRU irq\n", pruUsesMcaspIrq ? "U" : "Not u"); + #if RTDM_PRUSS_IRQ_VERSION < 1 if(pruUsesMcaspIrq) { From 539ff32914d3a5ffeee3363035201e26790c3be2 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Wed, 1 Apr 2020 17:54:11 +0000 Subject: [PATCH 039/148] core/PRU: NOP refactoring, moving out the macro definitions to the PruArmCommon.h file --- core/PRU.cpp | 97 +++++++++++++++++------------------------- include/PruArmCommon.h | 53 ++++++++++++++++++++++- pru/pru_rtaudio.p | 27 ++---------- pru/pru_rtaudio_irq.p | 29 +++---------- 4 files changed, 99 insertions(+), 107 deletions(-) diff --git a/core/PRU.cpp b/core/PRU.cpp index 1760ca861..f0f165316 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -90,7 +90,7 @@ using namespace BelaHwComponent; #define PRU_MEM_DAC_LENGTH 0x2000 // Length of ADC+DAC memory, in bytes #define PRU_MEM_COMM_OFFSET 0x0 // Offset within PRU-SHARED RAM #define PRU_MEM_DIGITAL_OFFSET 0x1000 //Offset within PRU-SHARED RAM -#define MEM_DIGITAL_BUFFER1_OFFSET 0x400 //Start pointer to DIGITAL_BUFFER1, which is 256 words. +#define PRU_MEM_DIGITAL_BUFFER1_OFFSET 0x400 //Start pointer to DIGITAL_BUFFER1, which is 256 words. // 256 is the maximum number of frames allowed extern int gRTAudioVerbose; @@ -109,7 +109,7 @@ class PruMemory pruAudioInStart[0] = pruAudioOutStart[1] + audioOut.size() * sizeof(audioOut[0]); pruAudioInStart[1] = pruAudioInStart[0] + audioIn.size() * sizeof(audioIn[0]); pruDigitalStart[0] = pruSharedRam + PRU_MEM_DIGITAL_OFFSET; - pruDigitalStart[1] = pruSharedRam + PRU_MEM_DIGITAL_OFFSET + MEM_DIGITAL_BUFFER1_OFFSET; + pruDigitalStart[1] = pruSharedRam + PRU_MEM_DIGITAL_OFFSET + PRU_MEM_DIGITAL_BUFFER1_OFFSET; if(context->analogFrames > 0) { prussdrv_map_prumem (pruNumber == 0 ? PRUSS0_PRU0_DATARAM : PRUSS0_PRU1_DATARAM, (void**)&pruDataRam); @@ -186,27 +186,6 @@ class PruMemory InternalBelaContext* context; }; -// Offsets within CPU <-> PRU communication memory (4 byte slots) -#define PRU_SHOULD_STOP 0 -#define PRU_CURRENT_BUFFER 1 -#define PRU_BUFFER_MCASP_FRAMES 2 -#define PRU_SHOULD_SYNC 3 -#define PRU_SYNC_ADDRESS 4 -#define PRU_SYNC_PIN_MASK 5 -#define PRU_LED_ADDRESS 6 -#define PRU_LED_PIN_MASK 7 -#define PRU_FRAME_COUNT 8 -#define PRU_USE_SPI 9 -#define PRU_SPI_NUM_CHANNELS 10 -#define PRU_USE_DIGITAL 11 -#define PRU_PRU_NUMBER 12 -#define PRU_MUX_CONFIG 13 -#define PRU_MUX_END_CHANNEL 14 -#define PRU_BUFFER_SPI_FRAMES 15 -#define PRU_BOARD_FLAGS 16 -#define PRU_ERROR_OCCURRED 17 -#define PRU_ACTIVE_TDM_SLOTS 18 - static unsigned int* gDigitalPins = NULL; #define USERLED3_GPIO_BASE (Gpio::getBankAddress(1))// GPIO1(24) is user LED 3 @@ -603,70 +582,70 @@ void PRU::initialisePruCommon() default: break; } - pru_buffer_comm[PRU_BOARD_FLAGS] = board_flags; + pru_buffer_comm[PRU_COMM_BOARD_FLAGS] = board_flags; /* Set up flags */ - pru_buffer_comm[PRU_SHOULD_STOP] = 0; - pru_buffer_comm[PRU_CURRENT_BUFFER] = 0; + pru_buffer_comm[PRU_COMM_SHOULD_STOP] = 0; + pru_buffer_comm[PRU_COMM_CURRENT_BUFFER] = 0; unsigned int pruFrames; if(analog_enabled) pruFrames = hardware_analog_frames; else pruFrames = context->audioFrames / 2; // PRU assumes 8 "fake" channels when SPI is disabled - pru_buffer_comm[PRU_BUFFER_SPI_FRAMES] = pruFrames; + pru_buffer_comm[PRU_COMM_BUFFER_SPI_FRAMES] = pruFrames; pruBufferMcaspFrames = context->audioFrames; - pru_buffer_comm[PRU_BUFFER_MCASP_FRAMES] = pruBufferMcaspFrames; - pru_buffer_comm[PRU_SHOULD_SYNC] = 0; - pru_buffer_comm[PRU_SYNC_ADDRESS] = 0; - pru_buffer_comm[PRU_SYNC_PIN_MASK] = 0; - pru_buffer_comm[PRU_PRU_NUMBER] = pru_number; - pru_buffer_comm[PRU_ERROR_OCCURRED] = 0; - pru_buffer_comm[PRU_ACTIVE_TDM_SLOTS] = ((uint16_t)context->audioOutChannels & 0xFFFF) << 16 | ((uint16_t)(context->audioInChannels) & 0xFFFF); + pru_buffer_comm[PRU_COMM_BUFFER_MCASP_FRAMES] = pruBufferMcaspFrames; + pru_buffer_comm[PRU_COMM_SHOULD_SYNC] = 0; + pru_buffer_comm[PRU_COMM_SYNC_ADDRESS] = 0; + pru_buffer_comm[PRU_COMM_SYNC_PIN_MASK] = 0; + pru_buffer_comm[PRU_COMM_PRU_NUMBER] = pru_number; + pru_buffer_comm[PRU_COMM_ERROR_OCCURRED] = 0; + pru_buffer_comm[PRU_COMM_ACTIVE_CHANNELS] = ((uint16_t)context->audioOutChannels & 0xFFFF) << 16 | ((uint16_t)(context->audioInChannels) & 0xFFFF); /* Set up multiplexer info */ if(context->multiplexerChannels == 2) { - pru_buffer_comm[PRU_MUX_CONFIG] = 1; + pru_buffer_comm[PRU_COMM_MUX_CONFIG] = 1; } else if(context->multiplexerChannels == 4) { - pru_buffer_comm[PRU_MUX_CONFIG] = 2; + pru_buffer_comm[PRU_COMM_MUX_CONFIG] = 2; } else if(context->multiplexerChannels == 8) { - pru_buffer_comm[PRU_MUX_CONFIG] = 3; + pru_buffer_comm[PRU_COMM_MUX_CONFIG] = 3; } else { // we trust that the number of multiplexer channels has been // checked elsewhere - pru_buffer_comm[PRU_MUX_CONFIG] = 0; + pru_buffer_comm[PRU_COMM_MUX_CONFIG] = 0; } if(led_enabled) { if(Bela_hwContains(belaHw, BelaMiniCape)) { - pru_buffer_comm[PRU_LED_ADDRESS] = belaMiniLedBlueGpioBase; - pru_buffer_comm[PRU_LED_PIN_MASK] = belaMiniLedBlueGpioPinMask; + pru_buffer_comm[PRU_COMM_LED_ADDRESS] = belaMiniLedBlueGpioBase; + pru_buffer_comm[PRU_COMM_LED_PIN_MASK] = belaMiniLedBlueGpioPinMask; } else { - pru_buffer_comm[PRU_LED_ADDRESS] = USERLED3_GPIO_BASE; - pru_buffer_comm[PRU_LED_PIN_MASK] = USERLED3_PIN_MASK; + pru_buffer_comm[PRU_COMM_LED_ADDRESS] = USERLED3_GPIO_BASE; + pru_buffer_comm[PRU_COMM_LED_PIN_MASK] = USERLED3_PIN_MASK; } } else { - pru_buffer_comm[PRU_LED_ADDRESS] = 0; - pru_buffer_comm[PRU_LED_PIN_MASK] = 0; + pru_buffer_comm[PRU_COMM_LED_ADDRESS] = 0; + pru_buffer_comm[PRU_COMM_LED_PIN_MASK] = 0; } if(analog_enabled) { - pru_buffer_comm[PRU_USE_SPI] = 1; + pru_buffer_comm[PRU_COMM_USE_SPI] = 1; // TODO : a different number of channels for inputs and outputs // is not yet supported unsigned int analogChannels = context->analogInChannels; - pru_buffer_comm[PRU_SPI_NUM_CHANNELS] = analogChannels; + pru_buffer_comm[PRU_COMM_SPI_NUM_CHANNELS] = analogChannels; } else { - pru_buffer_comm[PRU_USE_SPI] = 0; - pru_buffer_comm[PRU_SPI_NUM_CHANNELS] = 0; + pru_buffer_comm[PRU_COMM_USE_SPI] = 0; + pru_buffer_comm[PRU_COMM_SPI_NUM_CHANNELS] = 0; } if(digital_enabled) { - pru_buffer_comm[PRU_USE_DIGITAL] = 1; + pru_buffer_comm[PRU_COMM_USE_DIGITAL] = 1; } else { - pru_buffer_comm[PRU_USE_DIGITAL] = 0; + pru_buffer_comm[PRU_COMM_USE_DIGITAL] = 0; } } @@ -817,7 +796,7 @@ int PRU::start(char * const filename) int PRU::testPruError() { - if (unsigned int errorCode = pru_buffer_comm[PRU_ERROR_OCCURRED]) + if (unsigned int errorCode = pru_buffer_comm[PRU_COMM_ERROR_OCCURRED]) { // only print warnings if we have been running for a while, or forced to do so bool verbose = (context->audioFramesElapsed > 5000) || gRTAudioVerbose; @@ -862,7 +841,7 @@ int PRU::testPruError() if(codec->startAudio(0)) { rt_fprintf(stderr, "Error restarting codec\n"); } - pru_buffer_comm[PRU_ERROR_OCCURRED] = 0; + pru_buffer_comm[PRU_COMM_ERROR_OCCURRED] = 0; // TODO: should restart PRU and codec from scratch return ret; } else { @@ -920,7 +899,7 @@ void PRU::loop(void *userData, void(*render)(BelaContext*, void*), bool highPerf // Which buffer the PRU was last processing static uint32_t lastPRUBuffer = 0; // Poll - while(pru_buffer_comm[PRU_CURRENT_BUFFER] == lastPRUBuffer && !Bela_stopRequested()) { + while(pru_buffer_comm[PRU_COMM_CURRENT_BUFFER] == lastPRUBuffer && !Bela_stopRequested()) { #ifdef BELA_USE_POLL task_sleep_ns(sleepTime); #endif /* BELA_USE_POLL */ @@ -930,7 +909,7 @@ void PRU::loop(void *userData, void(*render)(BelaContext*, void*), bool highPerf } } - lastPRUBuffer = pru_buffer_comm[PRU_CURRENT_BUFFER]; + lastPRUBuffer = pru_buffer_comm[PRU_COMM_CURRENT_BUFFER]; #endif /* BELA_USE_POLL || BELA_USE_BUSYWAIT */ #ifdef BELA_USE_RTDM // make sure we always sleep a tiny bit to prevent hanging the board @@ -971,10 +950,10 @@ void PRU::loop(void *userData, void(*render)(BelaContext*, void*), bool highPerf if(Bela_stopRequested()) break; - // pru_buffer_comm[PRU_CURRENT_BUFFER] will have been set by + // pru_buffer_comm[PRU_COMM_CURRENT_BUFFER] will have been set by // the PRU just before signalling ARM. We use buffer that is // not in use by the PRU - int pruBufferForArm = pru_buffer_comm[PRU_CURRENT_BUFFER] == 0 ? 1 : 0; + int pruBufferForArm = pru_buffer_comm[PRU_COMM_CURRENT_BUFFER] == 0 ? 1 : 0; pruMemory->copyFromPru(pruBufferForArm); // Convert short (16-bit) samples to float @@ -1009,7 +988,7 @@ void PRU::loop(void *userData, void(*render)(BelaContext*, void*), bool highPerf // If multiplexer is enabled, find out which channels we have by pulling out // the place that it ended. Based on the buffer size, we can work out the // mux setting for the beginning of the buffer. - int pruMuxReference = pru_buffer_comm[PRU_MUX_END_CHANNEL]; + int pruMuxReference = pru_buffer_comm[PRU_COMM_MUX_END_CHANNEL]; // Value from the PRU is ahead by 1 + (frame size % 8); correct that when unrolling here. @@ -1461,7 +1440,7 @@ void PRU::loop(void *userData, void(*render)(BelaContext*, void*), bool highPerf // half as many analog frames as audio frames uint32_t pruFramesPerBlock = pruBufferMcaspFrames; // read the PRU counter - uint32_t pruFrameCount = pru_buffer_comm[PRU_FRAME_COUNT]; + uint32_t pruFrameCount = pru_buffer_comm[PRU_COMM_FRAME_COUNT]; // we initialize lastPruFrameCount the first time we get here, // just in case the PRU is already ahead of us static uint32_t lastPruFrameCount = pruFrameCount - pruFramesPerBlock; @@ -1505,7 +1484,7 @@ void PRU::loop(void *userData, void(*render)(BelaContext*, void*), bool highPerf #endif /* BELA_USE_RTDM */ // Tell PRU to stop - pru_buffer_comm[PRU_SHOULD_STOP] = 1; + pru_buffer_comm[PRU_COMM_SHOULD_STOP] = 1; if(underrunLed.enabled()) underrunLed.clear(); diff --git a/include/PruArmCommon.h b/include/PruArmCommon.h index 1ba92231e..639bc6244 100644 --- a/include/PruArmCommon.h +++ b/include/PruArmCommon.h @@ -1,7 +1,7 @@ #ifndef PRU_ARM_COMMON_H #define PRU_ARM_COMMON_H -// this file is included by both Pru.h and pru/pru_rtaudio*.h +// this file is included by both core/Pru.cpp and pru/pru_rtaudio*.p #define BOARD_FLAGS_BELA_MINI 0 #define BOARD_FLAGS_CTAG_FACE 1 #define BOARD_FLAGS_CTAG_BEAST 2 @@ -19,4 +19,55 @@ #define ARM_ERROR_XDMAERR 5 #define ARM_ERROR_INVALID_INIT 6 +// Offsets within CPU <-> PRU communication memory (4 byte slots) +#define COMM_SHOULD_STOP 0 // Set to be nonzero when loop should stop +#define COMM_CURRENT_BUFFER 4 // Which buffer we are on +#define COMM_BUFFER_MCASP_FRAMES 8 // How many frames per buffer for audio +#define COMM_SHOULD_SYNC 12 // Whether to synchronise to an external clock +#define COMM_SYNC_ADDRESS 16 // Which memory address to find the GPIO on +#define COMM_SYNC_PIN_MASK 20 // Which pin to read for the sync +#define COMM_LED_ADDRESS 24 // Which memory address to find the status LED on +#define COMM_LED_PIN_MASK 28 // Which pin to write to change LED +#define COMM_FRAME_COUNT 32 // How many frames have elapse since beginning +#define COMM_USE_SPI 36 // Whether or not to use SPI ADC and DAC +#define COMM_SPI_NUM_CHANNELS 40 // Low 2 bits indicate 8 [0x3], 4 [0x1] or 2 [0x0] channels +#define COMM_USE_DIGITAL 44 // Whether or not to use DIGITAL +#define COMM_PRU_NUMBER 48 // Which PRU this code is running on +#define COMM_MUX_CONFIG 52 // Whether to use the mux capelet, and how many channels +#define COMM_MUX_END_CHANNEL 56 // Which mux channel the last buffer ended on +#define COMM_BUFFER_SPI_FRAMES 60 // How many frames per buffer for analog i/o +#define COMM_BOARD_FLAGS 64 // Flags for the board we are on (BOARD_FLAGS_... are defined in include/PruArmCommon.h) +#define COMM_ERROR_OCCURRED 68 // Signals the ARM CPU that an error happened +#define COMM_ACTIVE_CHANNELS 72 // How many TDM slots contain useful data + +// ARM accesses these memory locations as uint32_t +// to avoid duplication and mistakes, we use macros to generate the values for ARM +// pasm is stupid and doesn't know about __TIME__, so this gives us a clue that +// we are using clang/gcc and we can use some more advanced preprocessor +// directives in here to generate some C code +#ifdef __TIME__ +#define ENUM(NAME) PRU_ ## NAME = (NAME/4), +typedef enum { +ENUM(COMM_SHOULD_STOP) +ENUM(COMM_CURRENT_BUFFER) +ENUM(COMM_BUFFER_MCASP_FRAMES) +ENUM(COMM_SHOULD_SYNC) +ENUM(COMM_SYNC_ADDRESS) +ENUM(COMM_SYNC_PIN_MASK) +ENUM(COMM_LED_ADDRESS) +ENUM(COMM_LED_PIN_MASK) +ENUM(COMM_FRAME_COUNT) +ENUM(COMM_USE_SPI) +ENUM(COMM_SPI_NUM_CHANNELS) +ENUM(COMM_USE_DIGITAL) +ENUM(COMM_PRU_NUMBER) +ENUM(COMM_MUX_CONFIG) +ENUM(COMM_MUX_END_CHANNEL) +ENUM(COMM_BUFFER_SPI_FRAMES) +ENUM(COMM_BOARD_FLAGS) +ENUM(COMM_ERROR_OCCURRED) +ENUM(COMM_ACTIVE_CHANNELS) +} PruCommonFlags; +#endif // __TIME__ + #endif /* PRU_ARM_COMMON_H */ diff --git a/pru/pru_rtaudio.p b/pru/pru_rtaudio.p index 5773adf82..ebed8ef71 100644 --- a/pru/pru_rtaudio.p +++ b/pru/pru_rtaudio.p @@ -81,26 +81,7 @@ #define AD7699_SEQ_OFFSET 3 // sequencer (0 = disable, 3 = scan all) #define SHARED_COMM_MEM_BASE 0x00010000 // Location where comm flags are written -#define COMM_SHOULD_STOP 0 // Set to be nonzero when loop should stop -#define COMM_CURRENT_BUFFER 4 // Which buffer we are on -#define COMM_BUFFER_FRAMES 8 // How many frames per buffer -#define COMM_SHOULD_SYNC 12 // Whether to synchronise to an external clock -#define COMM_SYNC_ADDRESS 16 // Which memory address to find the GPIO on -#define COMM_SYNC_PIN_MASK 20 // Which pin to read for the sync -#define COMM_LED_ADDRESS 24 // Which memory address to find the status LED on -#define COMM_LED_PIN_MASK 28 // Which pin to write to change LED -#define COMM_FRAME_COUNT 32 // How many frames have elapse since beginning -#define COMM_USE_SPI 36 // Whether or not to use SPI ADC and DAC -#define COMM_NUM_CHANNELS 40 // Low 2 bits indicate 8 [0x3], 4 [0x1] or 2 [0x0] channels -#define COMM_USE_DIGITAL 44 // Whether or not to use DIGITAL -#define COMM_PRU_NUMBER 48 // Which PRU this code is running on -#define COMM_MUX_CONFIG 52 // Whether to use the mux capelet, and how many channels -#define COMM_MUX_END_CHANNEL 56 // Which mux channel the last buffer ended on -#define COMM_BUFFER_SPI_FRAMES 60 // Unused (used in pru_rtaudio_irq.p) -#define COMM_BOARD_FLAGS 64 // Flags for the board we are on (BOARD_FLAGS_... are defined in include/PruBoardFlags.h) -#define PRU_ERROR_OCCURRED 68 // Unused here -#define COMM_ACTIVE_TDM_SLOTS 72 // How many TDM slots contain useful data - + // General constants for McASP peripherals (used for audio codec) #define MCASP0_BASE 0x48038000 #define MCASP1_BASE 0x4803C000 @@ -863,7 +844,7 @@ SPI_FLAG_CHECK_DONE: QBBC SPI_INIT_DONE, reg_flags, FLAG_BIT_USE_SPI // Load the number of channels: valid values are 8, 4 or 2 - LBBO reg_num_channels, reg_comm_addr, COMM_NUM_CHANNELS, 4 + LBBO reg_num_channels, reg_comm_addr, COMM_SPI_NUM_CHANNELS, 4 QBGT SPI_NUM_CHANNELS_LT8, reg_num_channels, 8 // 8 > num_channels ? LDI reg_num_channels, 8 // If N >= 8, N = 8 QBA SPI_NUM_CHANNELS_DONE @@ -956,7 +937,7 @@ SPI_INIT_DONE: MCASP_REG_WRITE MCASP_AHCLKRCTL, 0x8001 // Internal clock, not inv, /2; irrelevant? // Calculate which TDM slots to activate - LBBO r2, reg_comm_addr, COMM_ACTIVE_TDM_SLOTS, 4 // How many audio channels? + LBBO r2, reg_comm_addr, COMM_ACTIVE_CHANNELS, 4 // How many audio channels? MOV r3, 0x1 // mask = (1 << numchannels) - 1 LSL r3, r3, r2 SUB r3, r3, 1 @@ -1007,7 +988,7 @@ MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 4) // Set RFRST MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 12) // Set XFRST // Initialisation - LBBO reg_frame_total, reg_comm_addr, COMM_BUFFER_FRAMES, 4 // Total frame count (SPI; 0.5x-2x for McASP) + LBBO reg_frame_total, reg_comm_addr, COMM_BUFFER_MCASP_FRAMES, 4 // Total frame count (SPI; 0.5x-2x for McASP) MOV reg_dac_buf0, 0 // DAC buffer 0 start pointer LSL reg_dac_buf1, reg_frame_total, 1 // DAC buffer 1 start pointer = N[ch]*2[bytes]*bufsize LMBD r2, reg_num_channels, 1 // Returns 1, 2 or 3 depending on the number of channels diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 6fd0db505..60ffdaa79 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -123,25 +123,6 @@ #define AD7699_SEQ_OFFSET 3 // sequencer (0 = disable, 3 = scan all) #define SHARED_COMM_MEM_BASE 0x00010000 // Location where comm flags are written -#define COMM_SHOULD_STOP 0 // Set to be nonzero when loop should stop -#define COMM_CURRENT_BUFFER 4 // Which buffer we are on -#define COMM_BUFFER_MCASP_FRAMES 8 // How many frames per buffer for audio -#define COMM_SHOULD_SYNC 12 // Whether to synchronise to an external clock -#define COMM_SYNC_ADDRESS 16 // Which memory address to find the GPIO on -#define COMM_SYNC_PIN_MASK 20 // Which pin to read for the sync -#define COMM_LED_ADDRESS 24 // Which memory address to find the status LED on -#define COMM_LED_PIN_MASK 28 // Which pin to write to change LED -#define COMM_FRAME_COUNT 32 // How many frames have elapse since beginning -#define COMM_USE_SPI 36 // Whether or not to use SPI ADC and DAC -#define COMM_NUM_CHANNELS 40 // Low 2 bits indicate 8 [0x3], 4 [0x1] or 2 [0x0] channels -#define COMM_USE_DIGITAL 44 // Whether or not to use DIGITAL -#define COMM_PRU_NUMBER 48 // Which PRU this code is running on -#define COMM_MUX_CONFIG 52 // Whether to use the mux capelet, and how many channels -#define COMM_MUX_END_CHANNEL 56 // Which mux channel the last buffer ended on -#define COMM_BUFFER_SPI_FRAMES 60 // How many frames per buffer for analog i/o -#define COMM_BOARD_FLAGS 64 // Flags for the board we are on (BOARD_FLAGS_... are defined in include/PruArmCommon.h) -#define COMM_ERROR_OCCURED 68 // Signals the ARM CPU that an error happened -#define COMM_ACTIVE_TDM_SLOTS 72 // How many TDM slots contain useful data // General constants for local PRU peripherals (used for interrupt configuration) #define PRU_ICSS_INTC_LOCAL 0x00020000 @@ -482,7 +463,7 @@ .macro SEND_ERROR_TO_ARM .mparam error MOV r27, error -SBBO r27, reg_comm_addr, COMM_ERROR_OCCURED, 4 +SBBO r27, reg_comm_addr, COMM_ERROR_OCCURRED, 4 MOV r31.b0, PRU_SYSTEM_EVENT_RTDM_WRITE_VALUE .endm @@ -579,8 +560,8 @@ SETINPUT: //if it is an input, set the relevant bit DONE: .endm -.macro READ_ACTIVE_TDM_SLOTS_INTO_FLAGS - LBBO r27, reg_comm_addr, COMM_ACTIVE_TDM_SLOTS, 4 +.macro READ_ACTIVE_CHANNELS_INTO_FLAGS + LBBO r27, reg_comm_addr, COMM_ACTIVE_CHANNELS, 4 // the high word contains the number of outputs LSR r28, r27, 16 LSL r28, r28, FLAG_BIT_AUDIO_OUT_CHANNELS0 @@ -1246,7 +1227,7 @@ SPI_FLAG_CHECK_DONE: QBBC SPI_INIT_DONE, reg_flags, FLAG_BIT_USE_SPI // Load the number of channels: valid values are 8, 4 or 2 - LBBO reg_num_channels, reg_comm_addr, COMM_NUM_CHANNELS, 4 + LBBO reg_num_channels, reg_comm_addr, COMM_SPI_NUM_CHANNELS, 4 QBGT SPI_NUM_CHANNELS_LT8, reg_num_channels, 8 // 8 > num_channels ? LDI reg_num_channels, 8 // If N >= 8, N = 8 QBA SPI_NUM_CHANNELS_DONE @@ -1350,7 +1331,7 @@ SPI_INIT_DONE: MCASP_REG_WRITE MCASP_RMASK, MCASP_DATA_MASK // 16 bit data receive // Check how many channels we have - READ_ACTIVE_TDM_SLOTS_INTO_FLAGS + READ_ACTIVE_CHANNELS_INTO_FLAGS GET_NUM_AUDIO_IN_CHANNELS r2 GET_NUM_AUDIO_OUT_CHANNELS r3 // And that they are a valid number From 65851a5c75356b248a0d09f0638c07c29f61273a Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Wed, 1 Apr 2020 22:01:55 +0000 Subject: [PATCH 040/148] PRU: the computation of many McASP config registers is now devolved to ARM. PRU only loads them from shared memory and uses them as they are. The only difference remaining between BELA_TLV32 and BELA_MULTI_TLV in the PRU code is in the way the I/O is performed, but all the init is now the same for both. CTAG is largely broken at this point. --- core/I2c_Codec.cpp | 18 ++++++ core/I2c_MultiTLVCodec.cpp | 26 ++++++++ core/PRU.cpp | 14 +++-- core/RTAudio.cpp | 2 +- core/Spi_Codec.cpp | 4 ++ include/AudioCodec.h | 28 ++++++++- include/I2c_Codec.h | 9 +-- include/I2c_MultiTLVCodec.h | 2 + include/PRU.h | 17 +----- include/PruArmCommon.h | 14 +++++ include/Spi_Codec.h | 2 + pru/pru_rtaudio_irq.p | 118 ++++++++++-------------------------- 12 files changed, 140 insertions(+), 114 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 9dcd22ab5..0ee3ea660 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -722,3 +722,21 @@ I2c_Codec::~I2c_Codec() stopAudio(); } +const McaspConfig& I2c_Codec::getMcaspConfig() { +#define BELA_TLV_MCASP_DATA_FORMAT_TX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits +#define BELA_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits +#define BELA_TLV_MCASP_ACLKRCTL_VALUE 0x00 // External clk, polarity (falling edge) +#define BELA_TLV_MCASP_ACLKXCTL_VALUE 0x00 // External clk, polarity (falling edge) +#define BELA_TLV_MCASP_AFSXCTL_VALUE 0x100 // 2 Slot I2S, external fsclk, polarity (rising edge), single bit +#define BELA_TLV_MCASP_AFSRCTL_VALUE 0x100 // 2 Slot I2S, external fsclk, polarity (rising edge), single bit +#define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 2) // AHCLKX and AXR2 outputs + + mcaspConfig.xfmt = BELA_TLV_MCASP_DATA_FORMAT_TX_VALUE; + mcaspConfig.aclkxctl = BELA_TLV_MCASP_ACLKXCTL_VALUE; + mcaspConfig.afsxctl = BELA_TLV_MCASP_AFSXCTL_VALUE; + mcaspConfig.rfmt = BELA_TLV_MCASP_DATA_FORMAT_RX_VALUE; + mcaspConfig.aclkrctl = BELA_TLV_MCASP_ACLKRCTL_VALUE; + mcaspConfig.afsrctl = BELA_TLV_MCASP_AFSRCTL_VALUE; + mcaspConfig.pdir = MCASP_OUTPUT_PINS; + return mcaspConfig; +} diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 2c27cb8bc..746869adc 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -265,3 +265,29 @@ I2c_MultiTLVCodec::~I2c_MultiTLVCodec() if(masterCodec) delete masterCodec; } + +const McaspConfig& I2c_MultiTLVCodec::getMcaspConfig() +{ +// Values below are for 16x 16-bit TDM slots +#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits +#define BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE 0x00 // External clk, polarity (falling edge) +#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits +#define BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE 0x00 // External clk, polarity (falling edge) +#ifdef CODEC_WCLK_MASTER +#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x800 // 16-slot TDM external fsclk, rising edge means beginning of frame +#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x800 // 16-slot TDM external fsclk, rising edge means beginning of frame +#define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 2) // AHCLKX and AXR2 outputs +#else // CODEC_WCLK_MASTER +#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x802 // 16-slot TDM internal fsclk, rising edge means beginning of frame +#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x802 // 16-slot TDM internal fsclk, rising edge means beginning of frame +#define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | MCASP_PIN_AFSX | (1 << 2) // AHCLKX, FSX, AXR2 outputs +#endif // CODEC_WCLK_MASTER + mcaspConfig.xfmt = BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE; + mcaspConfig.aclkxctl = BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE; + mcaspConfig.afsxctl = BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE; + mcaspConfig.rfmt = BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE; + mcaspConfig.aclkrctl = BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE; + mcaspConfig.afsrctl = BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE; + mcaspConfig.pdir = MCASP_OUTPUT_PINS; + return mcaspConfig; +} diff --git a/core/PRU.cpp b/core/PRU.cpp index f0f165316..577264e41 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -558,7 +558,7 @@ int PRU::initialise(BelaHw newBelaHw, int pru_num, bool uniformSampleRate, int m return 0; } -void PRU::initialisePruCommon() +void PRU::initialisePruCommon(const McaspConfig& mcaspConfig) { uint32_t board_flags = 0; switch(belaHw) { @@ -600,7 +600,13 @@ void PRU::initialisePruCommon() pru_buffer_comm[PRU_COMM_PRU_NUMBER] = pru_number; pru_buffer_comm[PRU_COMM_ERROR_OCCURRED] = 0; pru_buffer_comm[PRU_COMM_ACTIVE_CHANNELS] = ((uint16_t)context->audioOutChannels & 0xFFFF) << 16 | ((uint16_t)(context->audioInChannels) & 0xFFFF); - + pru_buffer_comm[PRU_COMM_MCASP_CONF_XFMT] = mcaspConfig.xfmt; + pru_buffer_comm[PRU_COMM_MCASP_CONF_ACLKXCTL] = mcaspConfig.aclkxctl; + pru_buffer_comm[PRU_COMM_MCASP_CONF_AFSXCTL] = mcaspConfig.afsxctl; + pru_buffer_comm[PRU_COMM_MCASP_CONF_RFMT] = mcaspConfig.rfmt; + pru_buffer_comm[PRU_COMM_MCASP_CONF_ACLKRCTL] = mcaspConfig.aclkrctl; + pru_buffer_comm[PRU_COMM_MCASP_CONF_AFSRCTL] = mcaspConfig.afsrctl; + pru_buffer_comm[PRU_COMM_MCASP_CONF_PDIR] = mcaspConfig.pdir; /* Set up multiplexer info */ if(context->multiplexerChannels == 2) { pru_buffer_comm[PRU_COMM_MUX_CONFIG] = 1; @@ -650,7 +656,7 @@ void PRU::initialisePruCommon() } // Run the code image in the specified file -int PRU::start(char * const filename) +int PRU::start(char * const filename, const McaspConfig& mcaspConfig) { switch(belaHw) { @@ -753,7 +759,7 @@ int PRU::start(char * const filename) #endif /* RTDM_PRUSS_IRQ_VERSION >= 1 */ #endif /* BELA_USE_RTDM */ pru_buffer_comm = pruMemory->getPruBufferComm(); - initialisePruCommon(); + initialisePruCommon(mcaspConfig); unsigned int* pruCode; unsigned int pruCodeSize; diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 4870485a0..733f705af 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -706,7 +706,7 @@ static int startAudioInline(){ } // initialize and run the PRU - if(gPRU->start(gPRUFilename)) { + if(gPRU->start(gPRUFilename, gAudioCodec->getMcaspConfig())) { fprintf(stderr, "Error: unable to start PRU from %s\n", gPRUFilename[0] ? "embedded binary" : gPRUFilename); return -1; } diff --git a/core/Spi_Codec.cpp b/core/Spi_Codec.cpp index f3cfe57d9..110883e93 100644 --- a/core/Spi_Codec.cpp +++ b/core/Spi_Codec.cpp @@ -352,3 +352,7 @@ int Spi_Codec::_spiTransfer(unsigned char* tx_buf, unsigned char* rx_buf, size_t return 0; } + +const McaspConfig& Spi_Codec::getMcaspConfig() { + return mcaspConfig; +} diff --git a/include/AudioCodec.h b/include/AudioCodec.h index 27345ea75..a0b25b045 100644 --- a/include/AudioCodec.h +++ b/include/AudioCodec.h @@ -1,5 +1,27 @@ -#ifndef AUDIOCODEC_H_ -#define AUDIOCODEC_H_ +#pragma once +#include + +const uint32_t MCASP_PIN_AFSX = 1 << 28; +const uint32_t MCASP_PIN_AHCLKX = 1 << 27; +const uint32_t MCASP_PIN_ACLKX = 1 << 26; +const uint32_t MCASP_PIN_AMUTE = 1 << 25; // Also, 0 to 3 are XFR0 to XFR3 + +struct McaspConfig { +// TODO: ideally we would want to have methods to set each of these parameters within each register: +// ACLK:- falling/rising edge of bclk +// AFS:- falling/rising edge of wclk +// AFS: - wclk source +// AFS: - num slots +// FMT: - slot width +// FMT: - bit delay + uint32_t xfmt; + uint32_t aclkxctl; + uint32_t afsxctl; + uint32_t rfmt; + uint32_t aclkrctl; + uint32_t afsrctl; + uint32_t pdir; +}; class AudioCodec { @@ -14,5 +36,5 @@ class AudioCodec virtual int setHPVolume(int halfDbSteps) = 0; virtual int disable() = 0; virtual int reset() = 0; + virtual const McaspConfig& getMcaspConfig() = 0; }; -#endif /* AUDIOCODEC_H_ */ diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index d97505c43..1a962a58b 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -12,9 +12,7 @@ * Author: Andrew McPherson */ - -#ifndef I2CCODEC_H_ -#define I2CCODEC_H_ +#pragma once #include "AudioCodec.h" #include "I2c.h" @@ -70,18 +68,17 @@ class I2c_Codec : public I2c, public AudioCodec I2c_Codec(int i2cBus, int I2cAddress, CodecType type, bool verbose = false); ~I2c_Codec(); + const McaspConfig& getMcaspConfig(); private: int configureDCRemovalIIR(bool enable); //called by startAudio() int codecType; int dacVolumeHalfDbs; int adcVolumeHalfDbs; int hpVolumeHalfDbs; + McaspConfig mcaspConfig; bool generatesBclk; bool generatesWclk; bool running; bool verbose; bool hpEnabled; }; - - -#endif /* I2CCODEC_H_ */ diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index aaefb7c8a..c3984138a 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -33,6 +33,7 @@ class I2c_MultiTLVCodec : public AudioCodec void debugWriteRegister(int codecNum, int regNum, int value); int debugReadRegister(int codecNum, int regNum); + const McaspConfig& getMcaspConfig(); I2c_MultiTLVCodec(int i2cBus, int i2cAddress, bool verbose = false); ~I2c_MultiTLVCodec(); @@ -40,6 +41,7 @@ class I2c_MultiTLVCodec : public AudioCodec private: I2c_Codec *masterCodec; std::vector extraCodecs; + McaspConfig mcaspConfig; bool running; bool verbose; diff --git a/include/PRU.h b/include/PRU.h index 11d559c79..c9b7a1c9e 100644 --- a/include/PRU.h +++ b/include/PRU.h @@ -1,12 +1,4 @@ -/* - * PRU.h - * - * Created on: May 27, 2014 - * Author: andrewm - */ - -#ifndef PRU_H_ -#define PRU_H_ +#pragma once #include #include "Bela.h" @@ -172,7 +164,7 @@ class PRU int stopButtonPin, bool enableLed); // Run the code image in pru_rtaudio_bin.h - int start(char * const filename); + int start(char * const filename, const McaspConfig& mcaspConfig); // Loop: read and write data from the PRU and call the user-defined audio callback void loop(void *userData, void(*render)(BelaContext*, void*), bool highPerformanceMode); @@ -187,7 +179,7 @@ class PRU void exitPRUSS(); private: - void initialisePruCommon(); + void initialisePruCommon(const McaspConfig& mcaspConfig); int testPruError(); InternalBelaContext *context; // Overall settings @@ -218,6 +210,3 @@ class PRU Gpio underrunLed; // Flashing an LED upon underrun AudioCodec *codec; // Required to hard reset audio codec from loop }; - - -#endif /* PRU_H_ */ diff --git a/include/PruArmCommon.h b/include/PruArmCommon.h index 639bc6244..eb8b8f3d0 100644 --- a/include/PruArmCommon.h +++ b/include/PruArmCommon.h @@ -39,6 +39,13 @@ #define COMM_BOARD_FLAGS 64 // Flags for the board we are on (BOARD_FLAGS_... are defined in include/PruArmCommon.h) #define COMM_ERROR_OCCURRED 68 // Signals the ARM CPU that an error happened #define COMM_ACTIVE_CHANNELS 72 // How many TDM slots contain useful data +#define COMM_MCASP_CONF_XFMT 76 +#define COMM_MCASP_CONF_ACLKXCTL 80 +#define COMM_MCASP_CONF_AFSXCTL 84 +#define COMM_MCASP_CONF_RFMT 88 +#define COMM_MCASP_CONF_ACLKRCTL 92 +#define COMM_MCASP_CONF_AFSRCTL 96 +#define COMM_MCASP_CONF_PDIR 100 // ARM accesses these memory locations as uint32_t // to avoid duplication and mistakes, we use macros to generate the values for ARM @@ -67,6 +74,13 @@ ENUM(COMM_BUFFER_SPI_FRAMES) ENUM(COMM_BOARD_FLAGS) ENUM(COMM_ERROR_OCCURRED) ENUM(COMM_ACTIVE_CHANNELS) +ENUM(COMM_MCASP_CONF_XFMT) +ENUM(COMM_MCASP_CONF_ACLKXCTL) +ENUM(COMM_MCASP_CONF_AFSXCTL) +ENUM(COMM_MCASP_CONF_RFMT) +ENUM(COMM_MCASP_CONF_ACLKRCTL) +ENUM(COMM_MCASP_CONF_AFSRCTL) +ENUM(COMM_MCASP_CONF_PDIR) } PruCommonFlags; #endif // __TIME__ diff --git a/include/Spi_Codec.h b/include/Spi_Codec.h index 3c237276b..80cb66f25 100644 --- a/include/Spi_Codec.h +++ b/include/Spi_Codec.h @@ -56,12 +56,14 @@ class Spi_Codec : public AudioCodec { int setHPVolume(int halfDbSteps) {return 0;}; int setPga(float newGain, unsigned short int channel) {return 0;}; int disable() {return 0;}; + const McaspConfig& getMcaspConfig(); private: int _fd_master, _fd_slave; int _dacVolumethreeEighthsDbs; int _writeDACVolumeRegisters(bool mute); int _spiTransfer(unsigned char* tx_buf, unsigned char* rx_buf, size_t bytes, CODEC_TYPE codec = MASTER_CODEC); + McaspConfig mcaspConfig; bool _isBeast = false; bool _verbose; }; diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 60ffdaa79..048a504a1 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -20,9 +20,6 @@ // See https://github.com/BelaPlatform/Bela/issues/480 #define CTAG_IGNORE_UNUSED_INPUT_TDM_SLOTS - -#undef CODEC_WCLK_MASTER // Match this with I2c_MultiTLVCodec.cpp - #define DBOX_CAPE // Define this to use new cape hardware #define CLOCK_BASE 0x44E00000 @@ -285,20 +282,10 @@ #define MCASP_RBUF MCASP_RBUF2 #endif -#define MCASP_PIN_AFSX (1 << 28) -#define MCASP_PIN_AHCLKX (1 << 27) -#define MCASP_PIN_ACLKX (1 << 26) -#define MCASP_PIN_AMUTE (1 << 25) // Also, 0 to 3 are XFR0 to XFR3 - #ifdef DBOX_CAPE -#ifdef CODEC_WCLK_MASTER -#define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 2) // AHCLKX and AXR2 outputs -#else -#define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | MCASP_PIN_AFSX | (1 << 2) // AHCLKX, FSX, AXR2 outputs -#endif -#else +#else // DBOX_CAPE #define MCASP_OUTPUT_PINS (1 << 3) // Which pins are outputs -#endif +#endif // DBOX_CAPE #define MCASP_DATA_MASK 0xFFFF // 16 bit data #define MCASP_AHCLKRCTL_VALUE 0x8001 // Internal clock, not inv, /2; irrelevant? @@ -335,40 +322,6 @@ #define CTAG_BEAST_MCASP_RINTCTL_VALUE MCASP_RINTCTL_VALUE #define CTAG_BEAST_MCASP_XINTCTL_VALUE MCASP_XINTCTL_VALUE -#define BELA_TLV_MCASP_DATA_FORMAT_TX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits -#define BELA_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits -#define BELA_TLV_MCASP_ACLKRCTL_VALUE 0x00 // External clk, polarity (falling edge) -#define BELA_TLV_MCASP_ACLKXCTL_VALUE 0x00 // External clk, polarity (falling edge) -#define BELA_TLV_MCASP_AHCLKRCTL_VALUE MCASP_AHCLKRCTL_VALUE -#define BELA_TLV_MCASP_AHCLKXCTL_VALUE MCASP_AHCLKXCTL_VALUE -#define BELA_TLV_MCASP_AFSRCTL_VALUE 0x100 // 2 Slot I2S, external fsclk, polarity (rising edge), single bit -#define BELA_TLV_MCASP_AFSXCTL_VALUE 0x100 // 2 Slot I2S, external fsclk, polarity (rising edge), single bit -#define BELA_TLV_MCASP_RTDM_VALUE 0x3 // Enable TDM slots 0 and 1 -#define BELA_TLV_MCASP_XTDM_VALUE 0x3 // Enable TDM slots 0 and 1 -#define BELA_TLV_MCASP_RINTCTL_VALUE MCASP_RINTCTL_VALUE -#define BELA_TLV_MCASP_XINTCTL_VALUE MCASP_XINTCTL_VALUE - -// Values below are for 16x 16-bit TDM slots - -#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits -#define BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE 0x00 // External clk, polarity (falling edge) -#define BELA_MULTI_TLV_MCASP_AHCLKRCTL_VALUE MCASP_AHCLKRCTL_VALUE -#define BELA_MULTI_TLV_MCASP_AHCLKXCTL_VALUE MCASP_AHCLKXCTL_VALUE -#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits -#define BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE 0x00 // External clk, polarity (falling edge) - -#ifdef CODEC_WCLK_MASTER -#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x800 // 16-slot TDM external fsclk, rising edge means beginning of frame -#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x800 // 16-slot TDM external fsclk, rising edge means beginning of frame -#else -#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x802 // 16-slot TDM internal fsclk, rising edge means beginning of frame -#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x802 // 16-slot TDM internal fsclk, rising edge means beginning of frame -#endif - -// RTDM and XTDM are calculated dynamically -#define BELA_MULTI_TLV_MCASP_RINTCTL_VALUE MCASP_RINTCTL_VALUE -#define BELA_MULTI_TLV_MCASP_XINTCTL_VALUE MCASP_XINTCTL_VALUE - #define C_MCASP_MEM C28 // Shared PRU mem // Flags for the flags register @@ -467,6 +420,11 @@ SBBO r27, reg_comm_addr, COMM_ERROR_OCCURRED, 4 MOV r31.b0, PRU_SYSTEM_EVENT_RTDM_WRITE_VALUE .endm +.macro IF_NOT_BELA_TLV32_OR_BELA_MULTI_TLV_JMP_TO +.mparam DEST + QBBS DEST, reg_flags, FLAG_BIT_CTAG +.endm + .macro IF_NOT_BELA_MINI_JMP_TO .mparam DEST QBBC DEST, reg_flags, FLAG_BIT_BELA_MINI @@ -1325,7 +1283,12 @@ SPI_INIT_DONE: MCASP_REG_WRITE MCASP_PWRIDLESYSCONFIG, 0x02 // Power on MCASP_REG_WRITE MCASP_PFUNC, 0x00 // All pins are McASP - MCASP_REG_WRITE MCASP_PDIR, MCASP_OUTPUT_PINS // Set pin direction +#ifdef DBOX_CAPE + LBBO r2, reg_comm_addr, COMM_MCASP_CONF_PDIR, 4 +#else // DBOX_CAPE + MOV r2, MCASP_OUTPUT_PINS +#endif // DBOX_CAPE + MCASP_REG_WRITE MCASP_PDIR, r2 // Set pin direction MCASP_REG_WRITE MCASP_DLBCTL, 0x00 MCASP_REG_WRITE MCASP_DITCTL, 0x00 MCASP_REG_WRITE MCASP_RMASK, MCASP_DATA_MASK // 16 bit data receive @@ -1354,20 +1317,15 @@ MCASP_SET_RX_NOT_CTAG_FACE: QBA MCASP_SET_RX_DONE MCASP_SET_RX_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ -#ifdef ENABLE_BELA_TLV32 - IF_NOT_BELA_TLV32_JMP_TO MCASP_SET_RX_NOT_BELA_TLV32 - MCASP_SET_RX BELA_TLV_MCASP_DATA_FORMAT_RX_VALUE, BELA_TLV_MCASP_AFSRCTL_VALUE, BELA_TLV_MCASP_ACLKRCTL_VALUE, BELA_TLV_MCASP_AHCLKRCTL_VALUE, BELA_TLV_MCASP_RTDM_VALUE, BELA_TLV_MCASP_RINTCTL_VALUE, MCASP_DATA_MASK + IF_NOT_BELA_TLV32_OR_BELA_MULTI_TLV_JMP_TO MCASP_SET_RX_NOT_BELA_TLV32_OR_BELA_MULTI_TLV + LBBO r1, reg_comm_addr, COMM_MCASP_CONF_RFMT, 4 + LBBO r2, reg_comm_addr, COMM_MCASP_CONF_AFSRCTL, 4 + LBBO r3, reg_comm_addr, COMM_MCASP_CONF_ACLKRCTL, 4 + GET_NUM_AUDIO_OUT_CHANNELS r4 + COMPUTE_TDM_MASK r4 + MCASP_SET_RX r1, r2, r3, MCASP_AHCLKRCTL_VALUE, r4, MCASP_RINTCTL_VALUE, MCASP_DATA_MASK QBA MCASP_SET_RX_DONE -MCASP_SET_RX_NOT_BELA_TLV32: -#endif /* ENABLE_BELA_TLV32 */ -#ifdef ENABLE_BELA_MULTI_TLV32 - IF_NOT_BELA_MULTI_TLV_JMP_TO MCASP_SET_RX_NOT_MULTI_TLV - GET_NUM_AUDIO_IN_CHANNELS r3 - COMPUTE_TDM_MASK r3 - MCASP_SET_RX BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE, BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE, BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE, BELA_MULTI_TLV_MCASP_AHCLKRCTL_VALUE, r3, BELA_MULTI_TLV_MCASP_RINTCTL_VALUE, MCASP_DATA_MASK - QBA MCASP_SET_RX_DONE -MCASP_SET_RX_NOT_MULTI_TLV: -#endif /* ENABLE_BELA_MULTI_TLV32 */ +MCASP_SET_RX_NOT_BELA_TLV32_OR_BELA_MULTI_TLV: MCASP_SET_RX_DONE: @@ -1384,21 +1342,17 @@ MCASP_SET_TX_NOT_CTAG_FACE: QBA MCASP_SET_TX_DONE MCASP_SET_TX_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ -#ifdef ENABLE_BELA_TLV32 - IF_NOT_BELA_TLV32_JMP_TO MCASP_SET_TX_NOT_BELA_TLV32 - MCASP_SET_TX BELA_TLV_MCASP_DATA_FORMAT_TX_VALUE, BELA_TLV_MCASP_AFSXCTL_VALUE, BELA_TLV_MCASP_ACLKXCTL_VALUE, BELA_TLV_MCASP_AHCLKXCTL_VALUE, BELA_TLV_MCASP_XTDM_VALUE, BELA_TLV_MCASP_XINTCTL_VALUE + IF_NOT_BELA_TLV32_OR_BELA_MULTI_TLV_JMP_TO MCASP_SET_TX_NOT_BELA_TLV32_OR_BELA_MULTI_TLV + + LBBO r1, reg_comm_addr, COMM_MCASP_CONF_XFMT, 4 + LBBO r2, reg_comm_addr, COMM_MCASP_CONF_AFSXCTL, 4 + LBBO r3, reg_comm_addr, COMM_MCASP_CONF_ACLKXCTL, 4 + GET_NUM_AUDIO_OUT_CHANNELS r4 + COMPUTE_TDM_MASK r4 + MCASP_SET_TX r1, r2, r3, MCASP_AHCLKXCTL_VALUE, r4, MCASP_XINTCTL_VALUE QBA MCASP_SET_TX_DONE -MCASP_SET_TX_NOT_BELA_TLV32: -#endif /* ENABLE_BELA_TLV32 */ -#ifdef ENABLE_BELA_MULTI_TLV32 - IF_NOT_BELA_MULTI_TLV_JMP_TO MCASP_SET_TX_NOT_MULTI_TLV - GET_NUM_AUDIO_OUT_CHANNELS r3 - COMPUTE_TDM_MASK r3 +MCASP_SET_TX_NOT_BELA_TLV32_OR_BELA_MULTI_TLV: - MCASP_SET_TX BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE, BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE, BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE, BELA_MULTI_TLV_MCASP_AHCLKXCTL_VALUE, r3, BELA_MULTI_TLV_MCASP_XINTCTL_VALUE - QBA MCASP_SET_TX_DONE -MCASP_SET_TX_NOT_MULTI_TLV: -#endif /* ENABLE_BELA_MULTI_TLV32 */ MCASP_SET_TX_DONE: MCASP_REG_WRITE_EXT MCASP_SRCTL_R, 0x02 // Set up receive serialiser @@ -2295,18 +2249,10 @@ CTAG_BEAST_16CH_ANALOG_CFG_END: QBA SET_REG_FRAMES_DONE SET_REG_FRAMES_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ -#ifdef ENABLE_BELA_TLV32 -IF_NOT_BELA_TLV32_JMP_TO SET_REG_FRAMES_NOT_BELA_TLV32 - MOV r14, reg_frame_mcasp_total - QBA SET_REG_FRAMES_DONE -SET_REG_FRAMES_NOT_BELA_TLV32: -#endif /* ENABLE_BELA_TLV32 */ -#ifdef ENABLE_BELA_MULTI_TLV32 -IF_NOT_BELA_MULTI_TLV_JMP_TO SET_REG_FRAMES_NOT_BELA_MULTI_TLV +IF_NOT_BELA_TLV32_OR_BELA_MULTI_TLV_JMP_TO SET_REG_FRAMES_NOT_BELA_TLV32_OR_BELA_MULTI_TLV MOV r14, reg_frame_mcasp_total QBA SET_REG_FRAMES_DONE -SET_REG_FRAMES_NOT_BELA_MULTI_TLV: -#endif /* ENABLE_BELA_MULTI_TLV32 */ +SET_REG_FRAMES_NOT_BELA_TLV32_OR_BELA_MULTI_TLV: SET_REG_FRAMES_DONE: From fe665b5bdf06b6f56136b8ddc9d669aef2925a39 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Wed, 1 Apr 2020 22:53:29 +0000 Subject: [PATCH 041/148] core: added methods to the codecs to report on channel count and sampling rate, so that initialisation in RTAudio.cpp can be simplified --- core/I2c_Codec.cpp | 12 +++++++++ core/I2c_MultiTLVCodec.cpp | 12 +++++++++ core/RTAudio.cpp | 49 +++---------------------------------- core/Spi_Codec.cpp | 18 ++++++++++++++ include/AudioCodec.h | 3 +++ include/I2c_Codec.h | 3 +++ include/I2c_MultiTLVCodec.h | 3 +++ include/Spi_Codec.h | 3 +++ 8 files changed, 57 insertions(+), 46 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 0ee3ea660..be382379f 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -740,3 +740,15 @@ const McaspConfig& I2c_Codec::getMcaspConfig() { mcaspConfig.pdir = MCASP_OUTPUT_PINS; return mcaspConfig; } + +unsigned int I2c_Codec::getNumIns(){ + return 2; +} + +unsigned int I2c_Codec::getNumOuts(){ + return 2; +} + +float I2c_Codec::getSampleRate() { + return 44100; +} diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 746869adc..520674a1f 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -291,3 +291,15 @@ const McaspConfig& I2c_MultiTLVCodec::getMcaspConfig() mcaspConfig.pdir = MCASP_OUTPUT_PINS; return mcaspConfig; } + +unsigned int I2c_MultiTLVCodec::getNumIns(){ + return 2 * numDetectedCodecs(); +} + +unsigned int I2c_MultiTLVCodec::getNumOuts(){ + return 2 * numDetectedCodecs(); +} + +float I2c_MultiTLVCodec::getSampleRate() { + return 44100; +} diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 733f705af..f795613a9 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -147,52 +147,9 @@ static int Bela_getHwConfigPrivate(BelaHw hw, BelaHwConfig* cfg, BelaHwConfigPri } } // set audio I/O - switch(hw) - { - case BelaHw_Bela: - //nobreak - case BelaHw_BelaMini: - //nobreak - case BelaHw_Salt: - cfg->audioInChannels = 2; - cfg->audioOutChannels = 2; - cfg->audioSampleRate = 44100; - break; - case BelaHw_BelaMiniMultiAudio: - if(gI2cMultiTLVCodec) { - if(gI2cMultiTLVCodec->numDetectedCodecs() > 0) { - cfg->audioInChannels = 2*gI2cMultiTLVCodec->numDetectedCodecs(); - cfg->audioOutChannels = 2*gI2cMultiTLVCodec->numDetectedCodecs(); - } - else { - cfg->audioInChannels = 2; - cfg->audioOutChannels = 2; - } - } - else { - cfg->audioInChannels = 2; - cfg->audioOutChannels = 2; - } - cfg->audioSampleRate = 44100; - break; - case BelaHw_CtagFace: - //nobreak - case BelaHw_CtagFaceBela: - cfg->audioInChannels = 4; - cfg->audioOutChannels = 8; - cfg->audioSampleRate = 48000; - break; - case BelaHw_CtagBeast: - //nobreak - case BelaHw_CtagBeastBela: - cfg->audioInChannels = 8; - cfg->audioOutChannels = 16; - cfg->audioSampleRate = 48000; - break; - case BelaHw_NoHw: - default: - return -1; // unrecognized hw - } + cfg->audioInChannels = cfg->activeCodec->getNumIns(); + cfg->audioOutChannels = cfg->activeCodec->getNumOuts(); + cfg->audioSampleRate = cfg->activeCodec->getSampleRate(); // set analogs: if(Bela_hwContains(hw, BelaCape)) { cfg->analogInChannels = 8; diff --git a/core/Spi_Codec.cpp b/core/Spi_Codec.cpp index 110883e93..9ea9a8239 100644 --- a/core/Spi_Codec.cpp +++ b/core/Spi_Codec.cpp @@ -356,3 +356,21 @@ int Spi_Codec::_spiTransfer(unsigned char* tx_buf, unsigned char* rx_buf, size_t const McaspConfig& Spi_Codec::getMcaspConfig() { return mcaspConfig; } + +unsigned int Spi_Codec::getNumIns(){ + if(_isBeast) + return 8; + else + return 4; +} + +unsigned int Spi_Codec::getNumOuts(){ + if(_isBeast) + return 16; + else + return 8; +} + +float Spi_Codec::getSampleRate() { + return 48000; +} diff --git a/include/AudioCodec.h b/include/AudioCodec.h index a0b25b045..6b7423c0e 100644 --- a/include/AudioCodec.h +++ b/include/AudioCodec.h @@ -30,6 +30,9 @@ class AudioCodec virtual int initCodec() = 0; virtual int startAudio(int parameter) = 0; virtual int stopAudio() = 0; + virtual unsigned int getNumIns() = 0; + virtual unsigned int getNumOuts() = 0; + virtual float getSampleRate() = 0; virtual int setPga(float newGain, unsigned short int channel) = 0; virtual int setDACVolume(int halfDbSteps) = 0; virtual int setADCVolume(int halfDbSteps) = 0; diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index 1a962a58b..5ba411450 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -37,6 +37,9 @@ class I2c_Codec : public I2c, public AudioCodec int startAudio(int dual_rate); int startAudio(bool dual_rate, bool generates_bclk, bool generates_wclk, bool tdm_mode, unsigned int slotSize, unsigned int startingSlot, unsigned int bitDelay); int stopAudio(); + unsigned int getNumIns(); + unsigned int getNumOuts(); + float getSampleRate(); int setPllJ(short unsigned int j); int setPllD(unsigned int d); diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index c3984138a..b5d9a5f6d 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -21,6 +21,9 @@ class I2c_MultiTLVCodec : public AudioCodec int initCodec(); int startAudio(int dual_rate); int stopAudio(); + unsigned int getNumIns(); + unsigned int getNumOuts(); + float getSampleRate(); int setPga(float newGain, unsigned short int channel); int setDACVolume(int halfDbSteps); diff --git a/include/Spi_Codec.h b/include/Spi_Codec.h index 80cb66f25..cdf10ad57 100644 --- a/include/Spi_Codec.h +++ b/include/Spi_Codec.h @@ -47,6 +47,9 @@ class Spi_Codec : public AudioCodec { int initCodec(); int startAudio(int dummy_parameter = 0); int stopAudio(); + unsigned int getNumIns(); + unsigned int getNumOuts(); + float getSampleRate(); int setDACVolume(int halfDbSteps); int dumpRegisters(); int reset(); // Hard reset of codec(s) From a77ca751e8568ddd30152114aa643334dd5eba83 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Thu, 2 Apr 2020 11:39:15 +0000 Subject: [PATCH 042/148] core: codec parameters can be set before it is started. This will allow the McASP settings to also be ready before the codec is started, in time to be passed to the PRU --- core/I2c_Codec.cpp | 103 +++++++++++++++++++++++-------------- core/I2c_MultiTLVCodec.cpp | 66 ++++++++++++++---------- core/RTAudio.cpp | 8 +++ include/AudioCodec.h | 9 ++++ include/I2c_Codec.h | 8 ++- 5 files changed, 121 insertions(+), 73 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index be382379f..f80128f9b 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -18,9 +18,15 @@ I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, CodecType type, bool isVerbose /*= false*/) : codecType(type), dacVolumeHalfDbs(0), adcVolumeHalfDbs(0), hpVolumeHalfDbs(0), - generatesBclk(true), generatesWclk(true), running(false) +running(false) { - setVerbose(isVerbose); + params.slotSize = 16; + params.startingSlot = 0; + params.bitDelay = 0; + params.dualRate = false; + params.tdmMode = false; + params.generatesBclk = true; + params.generatesWclk = true; initI2C_RW(i2cBus, i2cAddress, -1); } @@ -42,27 +48,8 @@ int I2c_Codec::initCodec() // Tell the codec to start generating audio // See the TLV320AIC3106 datasheet for full details of the registers -// The dual_rate flag, when true, runs the codec at 88.2kHz; otherwise -// it runs at 44.1kHz -int I2c_Codec::startAudio(int dual_rate) +int I2c_Codec::startAudio(int dummy) { - return startAudio(dual_rate, true, true, false, 16, 0, 0); -} - -// Start audio with more setting control -// generates_bclk: whether the codec generates the bit clock from its PLL -// generates_wclk: whether the codec generates the frame sync -// tdm_mode: whether to use TDM rather than I2S mode -// slotSize: size of a slot in bits -// startingSlot: where in the TDM frame to place the first channel - -int I2c_Codec::startAudio(bool dual_rate, bool generates_bclk, bool generates_wclk, - bool tdm_mode, unsigned int slotSize, unsigned int startingSlot, - unsigned int bitDelay) -{ - generatesBclk = generates_bclk; - generatesWclk = generates_wclk; - // As a best-practice it's safer not to assume the implementer has issued initCodec() // or has not otherwise modified codec registers since that call. // Explicit Switch to config register page 0: @@ -73,7 +60,7 @@ int I2c_Codec::startAudio(bool dual_rate, bool generates_bclk, bool generates_wc if(writeRegister(0x02, 0x00)) // Codec sample rate register: fs_ref / 1 return 1; - if(generatesBclk) { + if(params.generatesBclk) { // The sampling frequency is given as f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P) // The master clock PLLCLK_IN is 12MHz // K can be varied in intervals of resolution of 0.0001 up to 63.9999 @@ -94,7 +81,7 @@ int I2c_Codec::startAudio(bool dual_rate, bool generates_bclk, bool generates_wc return 1; } - if(dual_rate) { + if(params.dualRate) { if(writeRegister(0x07, 0xEA)) // Codec datapath register: 44.1kHz; dual rate; standard datapath return 1; } @@ -103,8 +90,8 @@ int I2c_Codec::startAudio(bool dual_rate, bool generates_bclk, bool generates_wc return 1; } - if(generatesBclk) { - if(generatesWclk) { + if(params.generatesBclk) { + if(params.generatesWclk) { if(writeRegister(0x08, 0xE0)) { // Audio serial control register A: BCLK, WCLK outputs, return 1; // DOUT tri-state when inactive } @@ -121,22 +108,30 @@ int I2c_Codec::startAudio(bool dual_rate, bool generates_bclk, bool generates_wc return 1; // DOUT tri-state when inactive } - if(tdm_mode) { + if(params.tdmMode) { + // Supported values of slot size in the PRU code: 16 and 32 bits. Note that + // altering slot size requires changing #defines in the PRU code. unsigned int crb; // Audio serial control register B - if(slotSize == 16) // The below values all enable 256-clock mode when Bclk is an output + switch(params.slotSize) {// The below values all enable 256-clock mode when Bclk is an output + case 16: crb = 0x48; - else if(slotSize == 20) + break; + case 20: crb = 0x58; - else if(slotSize == 24) + break; + case 24: crb = 0x68; - else if(slotSize == 32) + break; + case 32: crb = 0x78; - else + break; + default: return 1; + } - if(writeRegister(0x09, crb)) // Audio serial control register B: DSP mode, word len specified by slotSize + if(writeRegister(0x09, crb)) // Audio serial control register B: DSP/TDM mode, word len specified by slotSize return 1; - if(writeRegister(0x0A, startingSlot * slotSize + bitDelay)) // Audio serial control register C: specifying offset in bits + if(writeRegister(0x0A, params.startingSlot * params.slotSize + params.bitDelay)) // Audio serial control register C: specifying offset in bits return 1; } else { @@ -171,7 +166,7 @@ int I2c_Codec::startAudio(bool dual_rate, bool generates_bclk, bool generates_wc if(writeHPVolumeRegisters()) // Send DAC to high-power outputs return 1; - if(generatesBclk) { + if(params.generatesBclk) { if(writeRegister(0x66, 0x02)) // Clock generation control register: use MCLK, PLL N = 2 return 1; } @@ -197,7 +192,7 @@ int I2c_Codec::startAudio(bool dual_rate, bool generates_bclk, bool generates_wc // wait for the codec to stabilize before unmuting the HP amp. // this gets rid of the loud pop. - if(generatesBclk) + if(params.generatesBclk) usleep(10000); // note : a small click persists, but it is unavoidable @@ -211,7 +206,7 @@ int I2c_Codec::startAudio(bool dual_rate, bool generates_bclk, bool generates_wc if(writeDACVolumeRegisters(false)) // Unmute and set volume return 1; - if(generatesBclk) { + if(params.generatesBclk) { if(writeRegister(0x65, 0x00)) // GPIO control register B: disabled; codec uses PLLDIV_OUT return 1; } @@ -676,8 +671,8 @@ int I2c_Codec::disable(){ return 1; if(writeRegister(0x01, 0x80)) // Reset codec to defaults return 1; - if(generatesBclk) { - if(generatesWclk) { + if(params.generatesBclk) { + if(params.generatesWclk) { if(writeRegister(0x08, 0xE0)) { // Put codec in master mode (required for hi-z mode) return 1; } @@ -750,5 +745,33 @@ unsigned int I2c_Codec::getNumOuts(){ } float I2c_Codec::getSampleRate() { - return 44100; + if(params.dualRate) + return 88200; + else + return 44100; +} + +int I2c_Codec::setParameters(AudioCodecParams& codecParams) +{ + params = codecParams; + int ret = 0; + if(!params.generatesBclk && params.generatesWclk) { + verbose && fprintf(stderr, "I2c_Codec: cannot generate Wclk if it doesn't generate Bclk\n"); + ret = -1; + } + if(params.dualRate) { + verbose && fprintf(stderr, "I2c_Codec: dualRate is not tested\n"); + ret = -1; + } + if(params.bitDelay > 2) { + verbose && fprintf(stderr, "I2c_Codec: max bitDelay is 2\n"); + params.bitDelay = 2; + ret = -1; + } + if(!params.tdmMode && 0 != params.startingSlot) { + verbose && fprintf(stderr, "I2c_Codec: startingSlot has to be 0 in DSP mode\n"); + params.startingSlot = 0; + ret = -1; + } + return ret; } diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 520674a1f..cab8de226 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -42,15 +42,43 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(int i2cBus, int i2cAddress, bool isVerbose extraCodecs.push_back(testCodec); } } + // Master codec generates bclk (and possibly wclk) with its PLL + // and occupies the first two slots + const int slotSize = 16; + const unsigned int bitDelay = 0; + unsigned int slotNum = 0; + bool codecWclkMaster = +#ifdef CODEC_WCLK_MASTER + true; // Main codec generates word clock +#else + false; // AM335x generates word clock +#endif + + AudioCodecParams params; + params.slotSize = slotSize; + params.bitDelay = bitDelay; + params.dualRate = false; + params.tdmMode = true; + if(masterCodec) { + params.startingSlot = slotNum; + params.generatesBclk = true; + params.generatesWclk = codecWclkMaster; + masterCodec->setParameters(params); + } + params.generatesBclk = false; + params.generatesWclk = false; + for(auto& codec : extraCodecs) { + slotNum += 2; + params.startingSlot = slotNum; + codec->setParameters(params); + } } // This method initialises the audio codec to its default state int I2c_MultiTLVCodec::initCodec() { - int ret = 0; - if(!masterCodec) - return 1; - if((ret = masterCodec->initCodec())) + int ret = 1; + if(!masterCodec || (ret = masterCodec->initCodec())) return ret; std::vector::iterator it; @@ -65,34 +93,14 @@ int I2c_MultiTLVCodec::initCodec() // Tell the codec to start generating audio int I2c_MultiTLVCodec::startAudio(int dual_rate) { - // Supported values of slot size in the PRU code: 16 and 32 bits. Note that - // altering slot size requires changing #defines in the PRU code. - const int slotSize = 16; - unsigned int slotNum = 0; - unsigned int bitDelay = 0; - int ret; - - if(!masterCodec) - return 1; - - bool codecWclkMaster = -#ifdef CODEC_WCLK_MASTER - // Main codec generates word clock - true; -#else - // AM335x generates word clock - false; -#endif - // Master codec generates bclk (and possibly wclk) with its PLL - // and occupies the first two slots - if((ret = masterCodec->startAudio(dual_rate, true, codecWclkMaster, true, slotSize, slotNum, bitDelay))) + int ret = 1; + if(!masterCodec || (ret = masterCodec->startAudio(0))) return ret; // Each subsequent codec occupies the next 2 slots std::vector::iterator it; for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { - slotNum += 2; - if((ret = (*it)->startAudio(dual_rate, false, false, true, slotSize, slotNum, bitDelay))) + if((ret = (*it)->startAudio(0))) return ret; } @@ -301,5 +309,7 @@ unsigned int I2c_MultiTLVCodec::getNumOuts(){ } float I2c_MultiTLVCodec::getSampleRate() { - return 44100; + if(masterCodec) + return masterCodec->getSampleRate(); + return 0; } diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index f795613a9..a1b540912 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -150,6 +150,14 @@ static int Bela_getHwConfigPrivate(BelaHw hw, BelaHwConfig* cfg, BelaHwConfigPri cfg->audioInChannels = cfg->activeCodec->getNumIns(); cfg->audioOutChannels = cfg->activeCodec->getNumOuts(); cfg->audioSampleRate = cfg->activeCodec->getSampleRate(); + if(!cfg->audioInChannels && cfg->audioOutChannels) { + fprintf(stderr, "Error: 0 inputs and 0 outputs channels.\n"); + return -1; + } + if(!cfg->audioSampleRate) { + fprintf(stderr, "Error: audio sampling rate is 0. Is the codec enabled?\n"); + return -1; + } // set analogs: if(Bela_hwContains(hw, BelaCape)) { cfg->analogInChannels = 8; diff --git a/include/AudioCodec.h b/include/AudioCodec.h index 6b7423c0e..282080ea7 100644 --- a/include/AudioCodec.h +++ b/include/AudioCodec.h @@ -6,6 +6,15 @@ const uint32_t MCASP_PIN_AHCLKX = 1 << 27; const uint32_t MCASP_PIN_ACLKX = 1 << 26; const uint32_t MCASP_PIN_AMUTE = 1 << 25; // Also, 0 to 3 are XFR0 to XFR3 +struct AudioCodecParams { + unsigned int slotSize; // size of a slot in bits + unsigned int startingSlot; // what slot in the TDM frame to place the first channel in + unsigned int bitDelay; // additional offset in the TDM frame (in bits) + bool dualRate; // whether to run at single or double sampling rate + bool tdmMode; // whether to use TDM rather than DSP mode + bool generatesBclk; // whether the codec generates the bit clock + bool generatesWclk; // whether the codec generates the frame sync +}; struct McaspConfig { // TODO: ideally we would want to have methods to set each of these parameters within each register: // ACLK:- falling/rising edge of bclk diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index 5ba411450..222c1a2bc 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -17,7 +17,6 @@ #include "AudioCodec.h" #include "I2c.h" - class I2c_Codec : public I2c, public AudioCodec { short unsigned int pllJ; @@ -34,8 +33,8 @@ class I2c_Codec : public I2c, public AudioCodec int readRegister(unsigned int reg); int initCodec(); - int startAudio(int dual_rate); - int startAudio(bool dual_rate, bool generates_bclk, bool generates_wclk, bool tdm_mode, unsigned int slotSize, unsigned int startingSlot, unsigned int bitDelay); + int setParameters(AudioCodecParams& codecParams); + int startAudio(int dummy); int stopAudio(); unsigned int getNumIns(); unsigned int getNumOuts(); @@ -78,9 +77,8 @@ class I2c_Codec : public I2c, public AudioCodec int dacVolumeHalfDbs; int adcVolumeHalfDbs; int hpVolumeHalfDbs; + AudioCodecParams params; McaspConfig mcaspConfig; - bool generatesBclk; - bool generatesWclk; bool running; bool verbose; bool hpEnabled; From 2b42e50bfd296a10b419301608fee08c09b248ef Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 3 Apr 2020 12:26:13 +0000 Subject: [PATCH 043/148] core: McaspConfig is now a class in its own right, and it can programmatically set register values based on human-friendly parameters --- Makefile | 3 +- core/I2c_Codec.cpp | 36 ++++-- core/I2c_MultiTLVCodec.cpp | 11 +- core/Mcasp.cpp | 235 ++++++++++++++++++++++++++++++++++++ include/AudioCodec.h | 23 +--- include/I2c_MultiTLVCodec.h | 1 - include/Mcasp.h | 24 ++++ 7 files changed, 293 insertions(+), 40 deletions(-) create mode 100644 core/Mcasp.cpp create mode 100644 include/Mcasp.h diff --git a/Makefile b/Makefile index a1513990d..83fe2513e 100644 --- a/Makefile +++ b/Makefile @@ -393,8 +393,7 @@ ALL_DEPS += $(addprefix build/core/,$(notdir $(CORE_C_SRCS:.c=.d))) CORE_CPP_SRCS = $(filter-out core/default_main.cpp core/default_libpd_render.cpp, $(wildcard core/*.cpp)) CORE_OBJS := $(CORE_OBJS) $(addprefix build/core/,$(notdir $(CORE_CPP_SRCS:.cpp=.o))) -CORE_CORE_OBJS := build/core/RTAudio.o build/core/PRU.o build/core/RTAudioCommandLine.o build/core/I2c_Codec.o build/core/I2c_MultiTLVCodec.o build/core/Spi_Codec.o build/core/math_runfast.o build/core/GPIOcontrol.o build/core/PruBinary.o build/core/board_detect.o build/core/DataFifo.o build/core/BelaContextFifo.o build/core/BelaContextSplitter.o build/core/MiscUtilities.o build/core/Mmap.o -EXTRA_CORE_OBJS := $(filter-out $(CORE_CORE_OBJS), $(CORE_OBJS)) +CORE_CORE_OBJS := build/core/RTAudio.o build/core/PRU.o build/core/RTAudioCommandLine.o build/core/I2c_Codec.o build/core/I2c_MultiTLVCodec.o build/core/Spi_Codec.o build/core/math_runfast.o build/core/GPIOcontrol.o build/core/PruBinary.o build/core/board_detect.o build/core/DataFifo.o build/core/BelaContextFifo.o build/core/BelaContextSplitter.o build/core/MiscUtilities.o build/core/Mmap.o build/core/Mcasp.o ALL_DEPS += $(addprefix build/core/,$(notdir $(CORE_CPP_SRCS:.cpp=.d))) CORE_ASM_SRCS := $(wildcard core/*.S) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index f80128f9b..048a9fcc3 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -21,6 +21,7 @@ I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, CodecType type, bool isVerbose running(false) { params.slotSize = 16; + params.tdmSlots = 2; params.startingSlot = 0; params.bitDelay = 0; params.dualRate = false; @@ -717,7 +718,9 @@ I2c_Codec::~I2c_Codec() stopAudio(); } -const McaspConfig& I2c_Codec::getMcaspConfig() { +const McaspConfig& I2c_Codec::getMcaspConfig() +{ +/* #define BELA_TLV_MCASP_DATA_FORMAT_TX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits #define BELA_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits #define BELA_TLV_MCASP_ACLKRCTL_VALUE 0x00 // External clk, polarity (falling edge) @@ -725,14 +728,31 @@ const McaspConfig& I2c_Codec::getMcaspConfig() { #define BELA_TLV_MCASP_AFSXCTL_VALUE 0x100 // 2 Slot I2S, external fsclk, polarity (rising edge), single bit #define BELA_TLV_MCASP_AFSRCTL_VALUE 0x100 // 2 Slot I2S, external fsclk, polarity (rising edge), single bit #define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 2) // AHCLKX and AXR2 outputs +*/ + bool externalSamplingOnRisingEdge = true; + bool wclkIsWord = false; + bool wclkIsInternal = !params.generatesWclk; + bool wclkFalling = false; + uint32_t numSlots; + if(params.tdmMode) + numSlots = 256 / params.slotSize; // codec is in 256-bit mode + else + numSlots = 2; + + int ret = mcaspConfig.setFmt(params.slotSize, params.bitDelay); + if(ret) + fprintf(stderr, "Error while setting FMT\n"); + ret = mcaspConfig.setAclkctl(externalSamplingOnRisingEdge); + if(ret) + fprintf(stderr, "Error while setting ACLKCTL\n"); + ret = mcaspConfig.setAfsctl(numSlots, wclkIsWord, wclkIsInternal, wclkFalling); + if(ret) + fprintf(stderr, "Error while setting AFSCTL\n"); + unsigned char axr = 1 << 2; + ret = mcaspConfig.setPdir(wclkIsInternal, axr); + if(ret) + fprintf(stderr, "Error while setting PDIR\n"); - mcaspConfig.xfmt = BELA_TLV_MCASP_DATA_FORMAT_TX_VALUE; - mcaspConfig.aclkxctl = BELA_TLV_MCASP_ACLKXCTL_VALUE; - mcaspConfig.afsxctl = BELA_TLV_MCASP_AFSXCTL_VALUE; - mcaspConfig.rfmt = BELA_TLV_MCASP_DATA_FORMAT_RX_VALUE; - mcaspConfig.aclkrctl = BELA_TLV_MCASP_ACLKRCTL_VALUE; - mcaspConfig.afsrctl = BELA_TLV_MCASP_AFSRCTL_VALUE; - mcaspConfig.pdir = MCASP_OUTPUT_PINS; return mcaspConfig; } diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index cab8de226..92b510cfe 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -276,6 +276,8 @@ I2c_MultiTLVCodec::~I2c_MultiTLVCodec() const McaspConfig& I2c_MultiTLVCodec::getMcaspConfig() { + return masterCodec->getMcaspConfig(); +/* // Values below are for 16x 16-bit TDM slots #define BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits #define BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE 0x00 // External clk, polarity (falling edge) @@ -290,14 +292,7 @@ const McaspConfig& I2c_MultiTLVCodec::getMcaspConfig() #define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x802 // 16-slot TDM internal fsclk, rising edge means beginning of frame #define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | MCASP_PIN_AFSX | (1 << 2) // AHCLKX, FSX, AXR2 outputs #endif // CODEC_WCLK_MASTER - mcaspConfig.xfmt = BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE; - mcaspConfig.aclkxctl = BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE; - mcaspConfig.afsxctl = BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE; - mcaspConfig.rfmt = BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE; - mcaspConfig.aclkrctl = BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE; - mcaspConfig.afsrctl = BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE; - mcaspConfig.pdir = MCASP_OUTPUT_PINS; - return mcaspConfig; +*/ } unsigned int I2c_MultiTLVCodec::getNumIns(){ diff --git a/core/Mcasp.cpp b/core/Mcasp.cpp new file mode 100644 index 000000000..a6ea28d2e --- /dev/null +++ b/core/Mcasp.cpp @@ -0,0 +1,235 @@ +#include "../include/Mcasp.h" +#include + +int McaspConfig::setFmt(unsigned int slotSize, unsigned int bitDelay) +{ + struct { + unsigned ROT : 3; + unsigned BUSEL : 1; + unsigned SSZ : 4; + unsigned PBIT : 5; + unsigned PAD : 2; + unsigned RVRS : 1; + unsigned DATADLY : 2; + unsigned : 14; + } s = {0}; + + int rotation = 32 - slotSize; + +//XDATDLY: 0-3h Transmit sync bit delay. +//0 0-bit delay. The first transmit data bit, AXRn, occurs in same ACLKX cycle +//as the transmit frame sync (AFSX). +//1h 1-bit delay. The first transmit data bit, AXRn, occurs one ACLKX cycle +//after the transmit frame sync (AFSX). +//2h 2-bit delay. The first transmit data bit, AXRn, occurs two ACLKX cycles +//after the transmit frame sync (AFSX). +//3h Reserved. + s.DATADLY = bitDelay; + +//15 XRVRS Transmit serial bitstream order. +//0 Bitstream is LSB first. No bit reversal is performed in transmit format bit +//reverse unit. +//1 Bitstream is MSB first. Bit reversal is performed in transmit format bit +//reverse unit. + s.RVRS = 1; + +//XPAD: 0-3h Pad value for extra bits in slot not belonging to word defined by +// XMASK. This field only applies to bits when XMASK[n] = 0. +// 0 Pad extra bits with 0. +// 1h Pad extra bits with 1. +// 2h Pad extra bits with one of the bits from the word as specified by XPBIT bits. +// 3h Reserved. + s.PAD = 0; + +//XPBIT: 0-1Fh XPBIT value determines which bit (as written by the CPU or DMA to +// XBUF[n]) is used to pad the extra bits before shifting. This field only +// applies when XPAD = 2h. +// 0 Pad with bit 0 value. +// 1-1Fh Pad with bit 1 to bit 31 value. + s.PBIT = 0; + +//XSSZ: 0-Fh Transmit slot size. +//0-2h Reserved. +//3h Slot size is 8 bits. +//4h Reserved. +//5h Slot size is 12 bits. +//6h Reserved. +//7h Slot size is 16 bits. +//8h Reserved. +//9h Slot size is 20 bits. +//Ah Reserved. +//Bh Slot size is 24 bits. +//Ch Reserved. +//Dh Slot size is 28 bits. +//Eh Reserved. +//Fh Slot size is 32 bits. + if(slotSize & 3 || slotSize < 8 || slotSize > 32) + return -1; + s.SSZ = (slotSize) / 2 - 1; + +// XBUSEL: Selects whether writes to serializer buffer XRBUF[n] originate from +// the configuration bus (CFG) or the data (DAT) port. +//0 Writes to XRBUF[n] originate from the data port. Writes to +//XRBUF[n] from the configuration bus are ignored with no effect +//to the McASP. +//1 Writes to XRBUF[n] originate from the configuration bus. Writes to +//XRBUF[n] from the data port are ignored with no effect to the McASP. + s.BUSEL = 0; + +//XROT: Right-rotation value for transmit rotate right format unit +//0 Rotate right by 0 (no rotation). +//1h Rotate right by 4 bit positions. +//2h Rotate right by 8 bit positions. +//3h Rotate right by 12 bit positions. +//4h Rotate right by 16 bit positions. +//5h Rotate right by 20 bit positions. +//6h Rotate right by 24 bit positions. +//7h Rotate right by 28 bit positions. + if(rotation & 3) // has to be a multiple of 4 + return -1; + s.ROT = rotation >> 2; + + memcpy(&xfmt, &s, sizeof(xfmt)); + rfmt = xfmt; + return 0; +} + +int McaspConfig::setAclkctl(bool externalRisingEdge) +{ + struct { + unsigned CLKDIV : 5; + unsigned CLKM : 1; + unsigned ASYNC : 1; + unsigned CLKP : 1; + unsigned : 24; + } s = {0}; + +// CLKXP: Transmit bitstream clock polarity select bit. +// 0 Rising edge. External receiver samples data on the falling edge of the +// serial clock, so the transmitter must shift data out on the rising edge of +// the serial clock. +// 1 Falling edge. External receiver samples data on the rising edge of the +// serial clock, so the transmitter must shift data out on the falling edge of +// the serial clock. + s.CLKP = !externalRisingEdge; + +// ASYNC: Transmit/receive operation asynchronous enable bit. +// 0 Synchronous. Transmit clock and frame sync provides the source for both +// the transmit and receive sections. +// 1 Asynchronous. Separate clock and frame sync used by transmit and receive +// sections. + s.ASYNC = 0; + +// CLKXM: Transmit bit clock source bit. +// 0 External transmit clock source from ACLKX pin. +// 1 Internal transmit clock source from output of programmable bit clock divider. + s.CLKM = 0; + +// CLKXDIV: 0-1Fh Transmit bit clock divide ratio bits determine the +// divide-down ratio from AHCLKX to ACLKX. +// 0 Divide-by-1. +// 1h Divide-by-2. +// 2h-1Fh Divide-by-3 to divide-by-32. + s.CLKDIV = 0; + + memcpy(&aclkxctl, &s, sizeof(aclkxctl)); + aclkrctl = aclkxctl; + return 0; +} + +int McaspConfig::setAfsctl(unsigned int numSlots, bool wclkIsWord, bool wclkIsInternal, bool wclkFalling) +{ + struct { + unsigned FSP : 1; + unsigned FSM : 1; + unsigned : 2; + unsigned FWID : 1; + unsigned : 2; + unsigned MOD : 9; + unsigned : 16; + } s = {0}; +// XMOD: 0-1FFh Transmit frame sync mode select bits. +// 0 Burst mode. +// 1h Reserved. +// 2h-20h 2-slot TDM (I2S mode) to 32-slot TDM. +// 21h-17Fh Reserved. +// 180h 384-slot DIT mode. +// 181h-1FFh Reserved. + if(numSlots > 32 || numSlots < 2) + return 1; + s.MOD = numSlots; +// FXWID: Transmit frame sync width select bit indicates the width of the +// transmit frame sync (AFSX) during its active period. +// 0 Single bit. +// 1 Single word. + s.FWID = wclkIsWord; +// FSXM: Transmit frame sync generation select bit. +// 0 Externally-generated transmit frame sync. +// 1 Internally-generated transmit frame sync. + s.FSM = wclkIsInternal; +// FSXP: Transmit frame sync polarity select bit. +//0 A rising edge on transmit frame sync (AFSX) indicates the beginning of a frame. +//1 A falling edge on transmit frame sync (AFSX) indicates the beginning of a frame. + s.FSP = wclkFalling; + memcpy(&afsxctl, &s, sizeof(afsxctl)); + afsrctl = afsxctl; + return 0; +} + +int McaspConfig::setPdir(bool wclkIsInternal, unsigned char axr) +{ + struct { + unsigned AXR : 6; + unsigned : 19; + unsigned AMUTE : 1; + unsigned ACLKX : 1; + unsigned AHCLKX : 1; + unsigned AFSX : 1; + unsigned ACLKR : 1; + unsigned AHCLKR : 1; + unsigned AFSR : 1; + } s = {0}; +// AFSR: Determines if AFSR pin functions as an input or output. +// 0 Pin functions as input. +// 1 Pin functions as output. + s.AFSR = 0; // we ignore this because we always use the AFSX signal instead +// AHCLKR: Determines if AHCLKR pin functions as an input or output. +// 0 Pin functions as input. +// 1 Pin functions as output. + s.AHCLKR = 0; +// ACLKR: Determines if ACLKR pin functions as an input or output. +// 0 Pin functions as input. +// 1 Pin functions as output. + s.ACLKR = 0; +// AFSX: Determines if AFSX pin functions as an input or output. +// 0 Pin functions as input. +// 1 Pin functions as output. + s.AFSX = wclkIsInternal; +// AHCLKX: Determines if AHCLKX pin functions as an input or output. +// 0 Pin functions as input. +// 1 Pin functions as output. + s.AHCLKX = 1; +// ACLKX: Determines if ACLKX pin functions as an input or output. +// 0 Pin functions as input. +// 1 Pin functions as output. + s.ACLKX = s.ACLKR; +// AMUTE: Determines if AMUTE pin functions as an input or output. +// 0 Pin functions as input. +// 1 Pin functions as output. + s.AMUTE = 0; +// AXR[5-0]: Determines if AXRn pin functions as an input or output. +// 0 Pin functions as input. +// 1 Pin functions as output + s.AXR = axr; + + memcpy(&pdir, &s, sizeof(pdir)); + return 0; +} + +#include + +void mcasp_test(const char* name, uint32_t val1, uint32_t val2) +{ + printf("mcasp %s %#10x %#10x %s\n", name, val1, val2, + val1 == val2 ? "SUCCESS" : "ERROR"); +} diff --git a/include/AudioCodec.h b/include/AudioCodec.h index 282080ea7..01efd1429 100644 --- a/include/AudioCodec.h +++ b/include/AudioCodec.h @@ -1,13 +1,10 @@ #pragma once #include - -const uint32_t MCASP_PIN_AFSX = 1 << 28; -const uint32_t MCASP_PIN_AHCLKX = 1 << 27; -const uint32_t MCASP_PIN_ACLKX = 1 << 26; -const uint32_t MCASP_PIN_AMUTE = 1 << 25; // Also, 0 to 3 are XFR0 to XFR3 +#include "Mcasp.h" struct AudioCodecParams { unsigned int slotSize; // size of a slot in bits + unsigned int tdmSlots; // how many tdm slots unsigned int startingSlot; // what slot in the TDM frame to place the first channel in unsigned int bitDelay; // additional offset in the TDM frame (in bits) bool dualRate; // whether to run at single or double sampling rate @@ -15,22 +12,6 @@ struct AudioCodecParams { bool generatesBclk; // whether the codec generates the bit clock bool generatesWclk; // whether the codec generates the frame sync }; -struct McaspConfig { -// TODO: ideally we would want to have methods to set each of these parameters within each register: -// ACLK:- falling/rising edge of bclk -// AFS:- falling/rising edge of wclk -// AFS: - wclk source -// AFS: - num slots -// FMT: - slot width -// FMT: - bit delay - uint32_t xfmt; - uint32_t aclkxctl; - uint32_t afsxctl; - uint32_t rfmt; - uint32_t aclkrctl; - uint32_t afsrctl; - uint32_t pdir; -}; class AudioCodec { diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index b5d9a5f6d..3bcba3464 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -44,7 +44,6 @@ class I2c_MultiTLVCodec : public AudioCodec private: I2c_Codec *masterCodec; std::vector extraCodecs; - McaspConfig mcaspConfig; bool running; bool verbose; diff --git a/include/Mcasp.h b/include/Mcasp.h new file mode 100644 index 000000000..d109fe98d --- /dev/null +++ b/include/Mcasp.h @@ -0,0 +1,24 @@ +#pragma once +#include +static const uint32_t MCASP_PIN_AFSX = 1 << 28; +static const uint32_t MCASP_PIN_AHCLKX = 1 << 27; +static const uint32_t MCASP_PIN_ACLKX = 1 << 26; +static const uint32_t MCASP_PIN_AMUTE = 1 << 25; // Also, 0 to 3 are XFR0 to XFR3 + +class McaspConfig +{ +public: + uint32_t xfmt; + uint32_t aclkxctl; + uint32_t afsxctl; + uint32_t rfmt; + uint32_t aclkrctl; + uint32_t afsrctl; + uint32_t pdir; + int setFmt(unsigned int slotSize, unsigned int bitDelay); + int setAclkctl(bool externalRisingEdge); + int setAfsctl(unsigned int numSlots, bool wclkIsWord, bool wclkIsInternal, bool wclkFalling); + int setPdir(bool wclkIsInternal, unsigned char axr); +}; + +void mcasp_test(const char* name, uint32_t val1, uint32_t val2); From 644ce1db7d4dafd6e2fb83a13b52c2b09bca7723 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 20 Jul 2020 18:04:56 +0000 Subject: [PATCH 044/148] board_detect: now compiling --- resources/tools/board_detect/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/tools/board_detect/Makefile b/resources/tools/board_detect/Makefile index 97566f903..3413c9e9b 100644 --- a/resources/tools/board_detect/Makefile +++ b/resources/tools/board_detect/Makefile @@ -1,8 +1,8 @@ CXX=g++ -tCXXFLAGS=-std=c++11 +CXXFLAGS=-std=c++11 BUILD=build $(shell mkdir -p build) -OBJS = $(BUILD)/GPIOcontrol.o $(BUILD)/Spi_Codec.o $(BUILD)/I2c_Codec.o $(BUILD)/board_detect.o $(BUILD)/main.o +OBJS = $(BUILD)/GPIOcontrol.o $(BUILD)/Spi_Codec.o $(BUILD)/I2c_Codec.o $(BUILD)/I2c_MultiTLVCodec.o $(BUILD)/board_detect.o $(BUILD)/main.o $(BUILD)/Mcasp.o CPPFLAGS=-I../../../include From 7c065a0d6c110d4e116168142f88af658ac73893 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Thu, 1 Apr 2021 17:34:53 +0100 Subject: [PATCH 045/148] board_detect: now allowing several different ways of calling board_detect. The most important change for the user is that now `board_detect` by itself will take into account the value set in ~/.bela/belaconfig. Refactored a bit RTAudio.cpp to try to rationalise it (meh) and avoid leaking resources (the disabledCodec was not being deleted) --- core/RTAudio.cpp | 90 ++++++++--------- core/board_detect.cpp | 48 ++++++---- include/Bela.h | 24 ++++- resources/tools/board_detect/main.cpp | 96 +++++++++++++------ .../tools/board_detect/test_board_detect.sh | 51 ++++++++++ 5 files changed, 211 insertions(+), 98 deletions(-) create mode 100755 resources/tools/board_detect/test_board_detect.sh diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index a1b540912..451fd70ae 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -120,36 +120,18 @@ typedef struct AudioCodec* disabledCodec; } BelaHwConfigPrivate; -static I2c_Codec* gI2cCodec = NULL; -static Spi_Codec* gSpiCodec = NULL; int gRTAudioVerbose = 0; // Verbosity level for debugging -static I2c_MultiTLVCodec* gI2cMultiTLVCodec = NULL; AudioCodec* gAudioCodec = NULL; +static AudioCodec* gDisabledCodec = NULL; static int Bela_getHwConfigPrivate(BelaHw hw, BelaHwConfig* cfg, BelaHwConfigPrivate* pcfg) { - if(gRTAudioVerbose) - printf("Bela_getHwConfigPrivate()\n"); - memset((void*)cfg, 0, sizeof(BelaHwConfig)); - cfg->digitalChannels = 16; - // set audio codec (order of the below statements is important) - if(pcfg) - { - if(BelaHw_BelaMiniMultiAudio == hw) { - cfg->activeCodec = gI2cMultiTLVCodec; - cfg->disabledCodec = gSpiCodec; - } else if(Bela_hwContains(hw, CtagCape)) { - pcfg->activeCodec = gSpiCodec; - pcfg->disabledCodec = gI2cCodec; - } else if (Bela_hwContains(hw, Tlv320aic3104)) { - pcfg->activeCodec = gI2cCodec; - pcfg->disabledCodec = gSpiCodec; - } - } // set audio I/O - cfg->audioInChannels = cfg->activeCodec->getNumIns(); - cfg->audioOutChannels = cfg->activeCodec->getNumOuts(); - cfg->audioSampleRate = cfg->activeCodec->getSampleRate(); + if(!cfg || ! pcfg) + return 1; + cfg->audioInChannels = pcfg->activeCodec->getNumIns(); + cfg->audioOutChannels = pcfg->activeCodec->getNumOuts(); + cfg->audioSampleRate = pcfg->activeCodec->getSampleRate(); if(!cfg->audioInChannels && cfg->audioOutChannels) { fprintf(stderr, "Error: 0 inputs and 0 outputs channels.\n"); return -1; @@ -171,6 +153,8 @@ static int Bela_getHwConfigPrivate(BelaHw hw, BelaHwConfig* cfg, BelaHwConfigPri BelaHwConfig* Bela_HwConfig_new(BelaHw hw) { BelaHwConfig* cfg = new BelaHwConfig; + // TODO: this will always return error because of nullptr. + // Codec detection needs to be factored out of Bela_initAudio if(Bela_getHwConfigPrivate(hw, cfg, nullptr)) { delete cfg; @@ -394,36 +378,53 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) } // Initialise the rendering environment: sample rates, frame counts, numbers of channels - BelaHw belaHw = Bela_detectHw(); - if(gRTAudioVerbose) - printf("Detected hardware: %s\n", getBelaHwName(belaHw).c_str()); - // Check for user-selected hardware + BelaHw actualHw = Bela_detectHw(BelaHwDetectMode_Cache); + if(gRTAudioVerbose) + printf("Detected hardware: %s\n", getBelaHwName(actualHw).c_str()); + // Check for user-selected hardware, either on the command line ... BelaHw userHw = settings->board; if(gRTAudioVerbose) - printf("Hardware specified by user: %s\n", getBelaHwName(settings->board).c_str()); + printf("Hardware specified at the command line: %s\n", getBelaHwName(settings->board).c_str()); if(userHw == BelaHw_NoHw) { - userHw = Bela_detectUserHw(); + userHw = Bela_detectHw(BelaHwDetectMode_UserOnly); // ... or in the user belaconfig if(gRTAudioVerbose) - printf("Hardware specified in belaconfig: %s\n", getBelaHwName(userHw).c_str()); + printf("Hardware specified in the user's belaconfig: %s\n", getBelaHwName(userHw).c_str()); } - if(userHw != BelaHw_NoHw && userHw != belaHw && Bela_checkHwCompatibility(userHw, belaHw)) + BelaHw belaHw; + if(userHw == actualHw) + belaHw = userHw; + else if(userHw != BelaHw_NoHw && Bela_checkHwCompatibility(userHw, actualHw)) belaHw = userHw; + else + belaHw = actualHw; if(gRTAudioVerbose) printf("Hardware to be used: %s\n", getBelaHwName(belaHw).c_str()); - // TODO: this is a bit dirty here, it should probably be in getHwConfig, which should probably contextually renamed - if(1 == Bela_hwContains(belaHw, CtagCape)) - gSpiCodec = new Spi_Codec(ctagSpidevGpioCs0, NULL); - else if(2 == Bela_hwContains(belaHw, CtagCape)) - gSpiCodec = new Spi_Codec(ctagSpidevGpioCs0, ctagSpidevGpioCs1); + // figure out which codec to use and which to disable if several are present and conflicting + unsigned int ctags; + if((ctags = Bela_hwContains(belaHw, CtagCape))) + { + if(1 == ctags) + gAudioCodec = new Spi_Codec(ctagSpidevGpioCs0, NULL); + else if (2 == ctags) + gAudioCodec = new Spi_Codec(ctagSpidevGpioCs0, ctagSpidevGpioCs1); + if(Bela_hwContains(actualHw, Tlv320aic3104)) + gDisabledCodec = new I2c_Codec(codecI2cBus, codecI2cAddress, I2c_Codec::TLV320AIC3104, gRTAudioVerbose); + } else if(belaHw == BelaHw_BelaMiniMultiAudio) - gI2cMultiTLVCodec = new I2c_MultiTLVCodec(codecI2cBus, codecI2cAddress, gRTAudioVerbose); - else - gI2cCodec = new I2c_Codec(codecI2cBus, codecI2cAddress, I2c_Codec::TLV320AIC3104, gRTAudioVerbose); + gAudioCodec = new I2c_MultiTLVCodec(codecI2cBus, codecI2cAddress, gRTAudioVerbose); + else if(Bela_hwContains(belaHw, Tlv320aic3104)) + { + gAudioCodec = new I2c_Codec(codecI2cBus, codecI2cAddress, I2c_Codec::TLV320AIC3104, gRTAudioVerbose); + if(Bela_hwContains(actualHw, CtagCape)) + gDisabledCodec = new Spi_Codec(ctagSpidevGpioCs0, ctagSpidevGpioCs1); + } - BelaHwConfig cfg; + BelaHwConfig cfg = {0}; BelaHwConfigPrivate pcfg; + pcfg.activeCodec = gAudioCodec; + pcfg.disabledCodec = gDisabledCodec; if(Bela_getHwConfigPrivate(belaHw, &cfg, &pcfg)) { fprintf(stderr, "Unrecognized Bela hardware: is a cape connected?\n"); @@ -844,10 +845,9 @@ void Bela_cleanupAudio() rt_task_delete(&gRTAudioThread); #endif - if(gPRU != 0) - delete gPRU; - if(gAudioCodec != 0) - delete gAudioCodec; + delete gPRU; + delete gAudioCodec; + delete gDisabledCodec; delete gBcf; if(gAmplifierMutePin >= 0) diff --git a/core/board_detect.cpp b/core/board_detect.cpp index bf6e8cb0d..6c071435e 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -10,9 +10,6 @@ #include "../include/bela_hw_settings.h" #include "../include/board_detect.h" - - - static const int EEPROM_NUMCHARS = 30; static char eeprom_str[EEPROM_NUMCHARS]; static void read_eeprom(){ @@ -151,7 +148,7 @@ std::string getBelaHwName(BelaHw hardware) hwName = "BelaMiniMultiAudio"; break; default: - hwName = ""; + hwName = "NoHardware"; break; } return hwName; @@ -199,19 +196,39 @@ static int write_config_file(std::string path, BelaHw hardware) return -1; } -BelaHw Bela_detectHw() +BelaHw Bela_detectHw(const BelaHwDetectMode mode) { + if(BelaHwDetectMode_User == mode || BelaHwDetectMode_UserOnly == mode) + { + std::string configPath = "/root/.bela/belaconfig"; + BelaHw hw = parse_config_file(configPath, "BOARD"); + if(hw != BelaHw_NoHw) + return hw; + if(BelaHwDetectMode_UserOnly == mode) + return BelaHw_NoHw; + else + return Bela_detectHw(BelaHwDetectMode_Cache); + } + std::string configPath = "/run/bela/belaconfig"; - BelaHw hw = parse_config_file(configPath, "HARDWARE"); - if(hw != BelaHw_NoHw) - return hw; + if(BelaHwDetectMode_Cache == mode || BelaHwDetectMode_CacheOnly == mode) + { + BelaHw hw = parse_config_file(configPath, "HARDWARE"); + if(hw != BelaHw_NoHw) + return hw; + if(BelaHwDetectMode_CacheOnly == mode) + return BelaHw_NoHw; + else + return Bela_detectHw(BelaHwDetectMode_Scan); + } + + BelaHw hw = BelaHw_NoHw; if(is_belamini()) { bool hasTlv32[4]; for(int i = 0; i < 4; i++) { hasTlv32[i] = detectTlv32(codecI2cBus, codecI2cAddress + i); - printf("codec at %d = %d\n", codecI2cAddress + i, hasTlv32[i]); } if(hasTlv32[1] || hasTlv32[2] || hasTlv32[3]) @@ -248,19 +265,8 @@ BelaHw Bela_detectHw() return hw; } -BelaHw Bela_detectUserHw() -{ - //TODO: Function not implemented yet. - //This should check for command line options first and - //check in /root/.bela/belaconfig. - std::string configPath = "/root/.bela/belaconfig"; - BelaHw hw = parse_config_file(configPath, "BOARD"); - if(hw != BelaHw_NoHw) - return hw; - return BelaHw_NoHw; -} - using namespace BelaHwComponent; +/// can I run userHw when I actually have detectedHw? bool Bela_checkHwCompatibility(BelaHw userHw, BelaHw detectedHw) { if(userHw == BelaHw_Bela && Bela_hwContains(detectedHw, BelaCape)) diff --git a/include/Bela.h b/include/Bela.h index 5534ddb77..d2d1c8cc1 100644 --- a/include/Bela.h +++ b/include/Bela.h @@ -27,10 +27,12 @@ #ifndef BELA_H_ #define BELA_H_ #define BELA_MAJOR_VERSION 1 -#define BELA_MINOR_VERSION 9 +#define BELA_MINOR_VERSION 10 #define BELA_BUGFIX_VERSION 0 // Version history / changelog: +// 1.10.0 +// - added parameter to Bela_detectHw(), and associated typedef. Added more values to the BelaHw enum. // 1.9.0 // - added Bela_HwConfig_{new,delete} // 1.8.0 @@ -41,7 +43,7 @@ // - INPUT and OUTPUT are now an enum // 1.6.0 // - added Bela_setUserData(), Bela_requestStop(), Bela_stopRequested() -// 1.5.0 +// 1.5.1 // - in BelaInitSettings, renamed unused members, preserving binary compatibility // 1.5.0 // - in BelaInitSettings, board becomes BelaHw @@ -112,6 +114,15 @@ BelaHwConfig* Bela_HwConfig_new(BelaHw hw); */ void Bela_HwConfig_delete(BelaHwConfig* cfg); +typedef enum +{ + BelaHwDetectMode_Scan, + BelaHwDetectMode_Cache, + BelaHwDetectMode_CacheOnly, + BelaHwDetectMode_User, + BelaHwDetectMode_UserOnly, +} BelaHwDetectMode; + #include // Useful constants @@ -682,8 +693,15 @@ void Bela_setVerboseLevel(int level); /** * \brief Detect what hardware we are running on. + * + * \param mode How to perform the detection. Possible values are: + * BelaHwDetect_Scan : perform an automatic detection by scanning the peripherals and busses available, and cache value in `/run/bela/` + * BelaHwDetect_Cache: read cached value from `/run/bela` first. If it does not exist, fall back to BelaHwDetect_Scan + * BelaHwDetect_CacheOnly: read cached value from `/run/bela`. If it does not exist, return BelaHw_NoHw + * BelaHwDetect_User: read user-specified value from `~/.bela`. If it does not exist, fall back to BelaHwDetect_Cache + * BelaHwDetect_UserOnly: read user-specified value from `~/.bela`. If it does not exist, return BelaHw_NoHw */ -BelaHw Bela_detectHw(void); +BelaHw Bela_detectHw(BelaHwDetectMode mode); // *** Audio control functions *** diff --git a/resources/tools/board_detect/main.cpp b/resources/tools/board_detect/main.cpp index e200d1f20..d882be942 100644 --- a/resources/tools/board_detect/main.cpp +++ b/resources/tools/board_detect/main.cpp @@ -1,34 +1,72 @@ #include -int main(){ - BelaHw hw = Bela_detectHw(); - switch(hw) +#include +#include +#include +#include "../../../include/board_detect.h" + +static void printHelp(const char* command) +{ + fprintf(stderr, "Detect the board we are running on.\n" + "Usage:\n" + " %s \n" + "Where is one of:\n" + " scan\n" + " scanWithCache\n" + " user (default)\n" + " userOnly\n" + " full\n" + " help\n" + "Each of these (except for `help' and `full') has the same role as the corresponding argument to `Bela_detectHw()' (see `Bela.h' for details). `full' performs each of the others in turn and prints all of the results in order\n", command); +} + + +int main(int argc, char* argv[]) +{ + char* lastArg = nullptr; + if(argc > 1) + lastArg = argv[argc - 1]; + std::vector modes; + if(lastArg) + { + std::string str(lastArg); + if("scan" == str) + modes.push_back(BelaHwDetectMode_Scan); + else if("cache" == str) + modes.push_back(BelaHwDetectMode_Cache); + else if("cacheOnly" == str) + modes.push_back(BelaHwDetectMode_CacheOnly); + else if("user" == str) + modes.push_back(BelaHwDetectMode_User); + else if("userOnly" == str) + modes.push_back(BelaHwDetectMode_UserOnly); + else if("all" == str) { + modes.push_back(BelaHwDetectMode_Scan); + modes.push_back(BelaHwDetectMode_Cache); + modes.push_back(BelaHwDetectMode_CacheOnly); + modes.push_back(BelaHwDetectMode_User); + modes.push_back(BelaHwDetectMode_UserOnly); + } else if("help" == str || "--help" == str) { + printHelp(argv[0]); + return 0; + } else { + fprintf(stderr, "Error: parameter `%s' invalid.\n", str.c_str()); + printHelp(argv[0]); + return 2; + } + } + int ret = 0; + if(0 == modes.size()) + modes.push_back(BelaHwDetectMode_User); + for(auto& mode : modes) { - case BelaHw_Bela: - printf("Bela\n"); - break; - case BelaHw_BelaMini: - printf("BelaMini\n"); - break; - case BelaHw_Salt: - printf("Salt\n"); - break; - case BelaHw_CtagFace: - printf("CtagFace\n"); - break; - case BelaHw_CtagBeast: - printf("CtagBeast\n"); - break; - case BelaHw_CtagFaceBela: - printf("CtagFaceBela\n"); - break; - case BelaHw_CtagBeastBela: - printf("CtagBeastBela\n"); - break; - case BelaHw_NoHw: - default: - printf("NoHardware\n"); - return 1; + BelaHw hw = Bela_detectHw(mode); + printf("%s\n", getBelaHwName(hw).c_str()); + if(BelaHw_NoHw == hw) + ret = 1; + ret = 0; } - return 0; + if(modes.size() > 1) + return 0; + else return ret; } diff --git a/resources/tools/board_detect/test_board_detect.sh b/resources/tools/board_detect/test_board_detect.sh new file mode 100755 index 000000000..b45de2038 --- /dev/null +++ b/resources/tools/board_detect/test_board_detect.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +SYSFILE=/run/bela/belaconfig +USERFILE=/root/.bela/belaconfig +BO_SY=CtagFace +BO_US=Salt +mkdir -p $(dirname $SYSFILE) +mkdir -p $(dirname $USERFILE) + +function cl_sy () { + rm -rf $SYSFILE +} +function cl_us () { + rm -rf $USERFILE +} +function cr_sy () { + echo HARDWARE=$BO_SY > $SYSFILE +} +function cr_us () { + echo BOARD=$BO_US > $USERFILE +} +NO_HW=NoHardware +cl_sy +BO_RE=`board_detect scan` + +function tst () { + TEST=`./board_detect $1` + [ "$TEST" == "$2" ] || { echo "Error: expected \`$2' for \`./board_detect.sh $1\`. obtained \`$TEST' instead" 2> /dev/null; exit 1; } +} +cl_sy +cl_us +tst cacheOnly $NO_HW +tst cacheOnly $NO_HW +tst scan $BO_RE +tst cacheOnly $BO_RE +cl_sy +tst cache $BO_RE +tst cacheOnly $BO_RE +cr_sy +tst cache $BO_SY +tst cacheOnly $BO_SY +cl_us +tst user $BO_SY +tst userOnly $NO_HW +cr_us +tst userOnly $BO_US +tst user $BO_US +tst "" $BO_US # calling board_detect with no arguments +echo "Success" +exit 0 + From 9fc151476e209c235e25749ab6d12e895243bf7c Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 6 Apr 2020 11:53:33 +0000 Subject: [PATCH 046/148] core: offloaded the computation of even more McASP registers to ARM --- core/I2c_Codec.cpp | 6 ++ core/I2c_MultiTLVCodec.cpp | 5 +- core/Mcasp.cpp | 125 +++++++++++++++++++++++++++++++++--- core/PRU.cpp | 15 ++--- core/RTAudio.cpp | 2 +- include/I2c_MultiTLVCodec.h | 1 + include/Mcasp.h | 44 +++++++++++-- include/PRU.h | 4 +- include/PruArmCommon.h | 21 ++++-- pru/pru_rtaudio_irq.p | 71 ++++++++++++++------ 10 files changed, 241 insertions(+), 53 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 048a9fcc3..2bd31751e 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -753,6 +753,12 @@ const McaspConfig& I2c_Codec::getMcaspConfig() if(ret) fprintf(stderr, "Error while setting PDIR\n"); + ret = mcaspConfig.setInChannels(2, {0}); + if(ret) + fprintf(stderr, "Error while setting input channels\n"); + ret = mcaspConfig.setOutChannels(2, {2}); + if(ret) + fprintf(stderr, "Error while setting output channels\n"); return mcaspConfig; } diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 92b510cfe..93ea1a897 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -276,7 +276,10 @@ I2c_MultiTLVCodec::~I2c_MultiTLVCodec() const McaspConfig& I2c_MultiTLVCodec::getMcaspConfig() { - return masterCodec->getMcaspConfig(); + mc = masterCodec->getMcaspConfig(); + mc.setInChannels(getNumIns(), {0}); + mc.setOutChannels(getNumOuts(), {2}); + return mc; /* // Values below are for 16x 16-bit TDM slots #define BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits diff --git a/core/Mcasp.cpp b/core/Mcasp.cpp index a6ea28d2e..0a5c8f387 100644 --- a/core/Mcasp.cpp +++ b/core/Mcasp.cpp @@ -1,6 +1,12 @@ #include "../include/Mcasp.h" #include +McaspConfig::McaspConfig() : + regs({0}) +{ + regs.rmask = regs.xmask = 0xFFFF; +} + int McaspConfig::setFmt(unsigned int slotSize, unsigned int bitDelay) { struct { @@ -89,8 +95,8 @@ int McaspConfig::setFmt(unsigned int slotSize, unsigned int bitDelay) return -1; s.ROT = rotation >> 2; - memcpy(&xfmt, &s, sizeof(xfmt)); - rfmt = xfmt; + memcpy(®s.xfmt, &s, sizeof(regs.xfmt)); + regs.rfmt = regs.xfmt; return 0; } @@ -132,8 +138,8 @@ int McaspConfig::setAclkctl(bool externalRisingEdge) // 2h-1Fh Divide-by-3 to divide-by-32. s.CLKDIV = 0; - memcpy(&aclkxctl, &s, sizeof(aclkxctl)); - aclkrctl = aclkxctl; + memcpy(®s.aclkxctl, &s, sizeof(regs.aclkxctl)); + regs.aclkrctl = regs.aclkxctl; return 0; } @@ -166,13 +172,13 @@ int McaspConfig::setAfsctl(unsigned int numSlots, bool wclkIsWord, bool wclkIsIn // FSXM: Transmit frame sync generation select bit. // 0 Externally-generated transmit frame sync. // 1 Internally-generated transmit frame sync. - s.FSM = wclkIsInternal; + s.FSM = wclkIsInternal; // FSXP: Transmit frame sync polarity select bit. //0 A rising edge on transmit frame sync (AFSX) indicates the beginning of a frame. //1 A falling edge on transmit frame sync (AFSX) indicates the beginning of a frame. s.FSP = wclkFalling; - memcpy(&afsxctl, &s, sizeof(afsxctl)); - afsrctl = afsxctl; + memcpy(®s.afsxctl, &s, sizeof(regs.afsxctl)); + regs.afsrctl = regs.afsxctl; return 0; } @@ -222,10 +228,113 @@ int McaspConfig::setPdir(bool wclkIsInternal, unsigned char axr) // 1 Pin functions as output s.AXR = axr; - memcpy(&pdir, &s, sizeof(pdir)); + memcpy(®s.pdir, &s, sizeof(regs.pdir)); + return 0; +} + +uint32_t McaspConfig::computeTdm(unsigned int numChannels) +{ +// XTDMS[31-0]: Transmitter mode during TDM time slot n. +// 0 Transmit TDM time slot n is inactive. The transmit serializer does not shift out data during this slot. +// 1 Transmit TDM time slot n is active. The transmit serializer shifts out +// data during this slot according to the serializer control register (SRCTL). + if(0 == numChannels) + return 0; + return (1 << numChannels) - 1; +} + +uint32_t McaspConfig::computeFifoctl(unsigned int numSerializers) +{ + struct { + unsigned NUMDMA : 8; + unsigned NUMEVT : 8; + unsigned ENA : 1; + unsigned : 15; + } s; +// WENA: Write FIFO enable bit. +// 0 Write FIFO is disabled. The WLVL bit in the Write FIFO status register (WFIFOSTS) is reset to 0 +// and pointers are initialized, that is, the Write FIFO is “flushed.” +// 1 Write FIFO is enabled. If Write FIFO is to be enabled, it must be enabled prior to taking McASP +// out of reset. + s.ENA = 1; // this should be masked out during the first write, and unmasked during a successive write immediately following the first + +// WNUMEVT: 0-FFh Write word count per DMA event (32-bit). When the Write FIFO has space for at least WNUMEVT +// words of data, then an AXEVT (transmit DMA event) is generated to the host/DMA controller. This +// value should be set to a non-zero integer multiple of the number of serializers enabled as +// transmitters. This value must be set prior to enabling the Write FIFO. +// 0 0 words +// 1h 1 word +// 2h 2 words +// 3h-40h 3 to 64 words +// 41h-FFh Reserved + s.NUMEVT = 0; // TODO: don't know why we keep it this way, but this is what was in our PRU code (as written by @henrix) + +// 7-0 WNUMDMA 0-FFh Write word count per transfer (32-bit words). Upon a transmit DMA event from the McASP, +// WNUMDMA words are transferred from the Write FIFO to the McASP. This value must equal the +// number of McASP serializers used as transmitters. This value must be set prior to enabling the +// Write FIFO. +// 0 0 words +// 1h 1 word +// 2h 2 words +// 3h-10h 3-16 words +// 11h-FFh Reserved + s.NUMDMA = numSerializers; + uint32_t ret; + memcpy(&ret, &s, sizeof(ret)); + return ret; +} + +int McaspConfig::setSrctln(unsigned int n, McaspConfig::SrctlMode mode, McaspConfig::SrctlDrive drive) +{ +// regs.srctln contains data corresponding to SRCTLn for n 0:3 (inclusive). Given +// how only the lower 4 bits of each are to be set at configuration time, we +// pack all of them in srctl0123 as groups of 8 bits + if(n >= 4) + return -1; + struct { + unsigned SRMOD : 2; + unsigned DISMOD : 2; + unsigned : 4; + } s = {0}; +// DISMOD: 0-3h Serializer pin drive mode bit. Drive on pin when in inactive TDM slot of transmit mode or when serializer +// is inactive. This field only applies if the pin is configured as a McASP pin (PFUNC = 0). +// 0 Drive on pin is 3-state. +// 1h Reserved. +// 2h Drive on pin is logic low. +// 3h Drive on pin is logic high. + s.DISMOD = (unsigned int)drive; +// 1-0 SRMOD 0-3h Serializer mode bit. +// 0 Serializer is inactive. +// 1h Serializer is transmitter. +// 2h Serializer is receiver. +// 3h Reserved. + s.SRMOD = mode; + memcpy(((uint8_t*)®s.srctln) + n, &s, 1); return 0; } +int McaspConfig::setChannels(unsigned int numChannels, std::vector& serializers, bool input) +{ + uint32_t tdm = computeTdm(numChannels / serializers.size()); + input ? regs.rtdm = tdm : regs.xtdm = tdm; + uint32_t fifoctl = computeFifoctl(serializers.size()); + input ? regs.rfifoctl = fifoctl : regs.wfifoctl = fifoctl; + int ret = 0; + for(auto const& s : serializers) + ret |= setSrctln(s, input ? SrctlMode_RX : SrctlMode_TX, SrctlDrive_TRISTATE); + return ret; +} + +int McaspConfig::setInChannels(unsigned int numChannels, std::vector serializers) +{ + return setChannels(numChannels, serializers, true); +} + +int McaspConfig::setOutChannels(unsigned int numChannels, std::vector serializers) +{ + return setChannels(numChannels, serializers, false); +} + #include void mcasp_test(const char* name, uint32_t val1, uint32_t val2) diff --git a/core/PRU.cpp b/core/PRU.cpp index 577264e41..2366a7ab2 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -558,7 +558,7 @@ int PRU::initialise(BelaHw newBelaHw, int pru_num, bool uniformSampleRate, int m return 0; } -void PRU::initialisePruCommon(const McaspConfig& mcaspConfig) +void PRU::initialisePruCommon(const McaspRegisters& mcaspRegisters) { uint32_t board_flags = 0; switch(belaHw) { @@ -600,13 +600,8 @@ void PRU::initialisePruCommon(const McaspConfig& mcaspConfig) pru_buffer_comm[PRU_COMM_PRU_NUMBER] = pru_number; pru_buffer_comm[PRU_COMM_ERROR_OCCURRED] = 0; pru_buffer_comm[PRU_COMM_ACTIVE_CHANNELS] = ((uint16_t)context->audioOutChannels & 0xFFFF) << 16 | ((uint16_t)(context->audioInChannels) & 0xFFFF); - pru_buffer_comm[PRU_COMM_MCASP_CONF_XFMT] = mcaspConfig.xfmt; - pru_buffer_comm[PRU_COMM_MCASP_CONF_ACLKXCTL] = mcaspConfig.aclkxctl; - pru_buffer_comm[PRU_COMM_MCASP_CONF_AFSXCTL] = mcaspConfig.afsxctl; - pru_buffer_comm[PRU_COMM_MCASP_CONF_RFMT] = mcaspConfig.rfmt; - pru_buffer_comm[PRU_COMM_MCASP_CONF_ACLKRCTL] = mcaspConfig.aclkrctl; - pru_buffer_comm[PRU_COMM_MCASP_CONF_AFSRCTL] = mcaspConfig.afsrctl; - pru_buffer_comm[PRU_COMM_MCASP_CONF_PDIR] = mcaspConfig.pdir; + memcpy((void*)(pru_buffer_comm + PRU_COMM_MCASP_CONF_PDIR), &mcaspRegisters, + sizeof(mcaspRegisters)); /* Set up multiplexer info */ if(context->multiplexerChannels == 2) { pru_buffer_comm[PRU_COMM_MUX_CONFIG] = 1; @@ -656,7 +651,7 @@ void PRU::initialisePruCommon(const McaspConfig& mcaspConfig) } // Run the code image in the specified file -int PRU::start(char * const filename, const McaspConfig& mcaspConfig) +int PRU::start(char * const filename, const McaspRegisters& mcaspRegisters) { switch(belaHw) { @@ -759,7 +754,7 @@ int PRU::start(char * const filename, const McaspConfig& mcaspConfig) #endif /* RTDM_PRUSS_IRQ_VERSION >= 1 */ #endif /* BELA_USE_RTDM */ pru_buffer_comm = pruMemory->getPruBufferComm(); - initialisePruCommon(mcaspConfig); + initialisePruCommon(mcaspRegisters); unsigned int* pruCode; unsigned int pruCodeSize; diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 451fd70ae..457d8d44a 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -672,7 +672,7 @@ static int startAudioInline(){ } // initialize and run the PRU - if(gPRU->start(gPRUFilename, gAudioCodec->getMcaspConfig())) { + if(gPRU->start(gPRUFilename, gAudioCodec->getMcaspConfig().regs)) { fprintf(stderr, "Error: unable to start PRU from %s\n", gPRUFilename[0] ? "embedded binary" : gPRUFilename); return -1; } diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index 3bcba3464..3c1b915d6 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -44,6 +44,7 @@ class I2c_MultiTLVCodec : public AudioCodec private: I2c_Codec *masterCodec; std::vector extraCodecs; + McaspConfig mc; bool running; bool verbose; diff --git a/include/Mcasp.h b/include/Mcasp.h index d109fe98d..e90e143d5 100644 --- a/include/Mcasp.h +++ b/include/Mcasp.h @@ -1,24 +1,54 @@ #pragma once #include +#include static const uint32_t MCASP_PIN_AFSX = 1 << 28; static const uint32_t MCASP_PIN_AHCLKX = 1 << 27; static const uint32_t MCASP_PIN_ACLKX = 1 << 26; static const uint32_t MCASP_PIN_AMUTE = 1 << 25; // Also, 0 to 3 are XFR0 to XFR3 -class McaspConfig +struct McaspRegisters { -public: - uint32_t xfmt; - uint32_t aclkxctl; - uint32_t afsxctl; + uint32_t pdir; + uint32_t rmask; uint32_t rfmt; - uint32_t aclkrctl; uint32_t afsrctl; - uint32_t pdir; + uint32_t aclkrctl; + uint32_t rtdm; + uint32_t xmask; + uint32_t xfmt; + uint32_t afsxctl; + uint32_t aclkxctl; + uint32_t xtdm; + uint32_t srctln; + uint32_t wfifoctl; + uint32_t rfifoctl; +}; + +class McaspConfig +{ +public: + typedef enum { + SrctlMode_DISABLED = 0, + SrctlMode_TX = 1, + SrctlMode_RX = 2, + } SrctlMode; + typedef enum { + SrctlDrive_TRISTATE = 0, + SrctlDrive_LOW = 2, + SrctlDrive_HIGH = 3, + } SrctlDrive; + McaspConfig(); int setFmt(unsigned int slotSize, unsigned int bitDelay); int setAclkctl(bool externalRisingEdge); int setAfsctl(unsigned int numSlots, bool wclkIsWord, bool wclkIsInternal, bool wclkFalling); int setPdir(bool wclkIsInternal, unsigned char axr); + int setSrctln(unsigned int n, SrctlMode mode, SrctlDrive drive); + int setInChannels(unsigned int numChannels, std::vector serializers); + int setOutChannels(unsigned int numChannels, std::vector serializers); + int setChannels(unsigned int numChannels, std::vector& serializers, bool input); + static uint32_t computeTdm(unsigned int numChannels); + static uint32_t computeFifoctl(unsigned int numSerializers); + McaspRegisters regs; }; void mcasp_test(const char* name, uint32_t val1, uint32_t val2); diff --git a/include/PRU.h b/include/PRU.h index c9b7a1c9e..30a7f74d5 100644 --- a/include/PRU.h +++ b/include/PRU.h @@ -164,7 +164,7 @@ class PRU int stopButtonPin, bool enableLed); // Run the code image in pru_rtaudio_bin.h - int start(char * const filename, const McaspConfig& mcaspConfig); + int start(char * const filename, const McaspRegisters& mcaspRegisters); // Loop: read and write data from the PRU and call the user-defined audio callback void loop(void *userData, void(*render)(BelaContext*, void*), bool highPerformanceMode); @@ -179,7 +179,7 @@ class PRU void exitPRUSS(); private: - void initialisePruCommon(const McaspConfig& mcaspConfig); + void initialisePruCommon(const McaspRegisters& mcaspRegisters); int testPruError(); InternalBelaContext *context; // Overall settings diff --git a/include/PruArmCommon.h b/include/PruArmCommon.h index eb8b8f3d0..977573b62 100644 --- a/include/PruArmCommon.h +++ b/include/PruArmCommon.h @@ -39,13 +39,22 @@ #define COMM_BOARD_FLAGS 64 // Flags for the board we are on (BOARD_FLAGS_... are defined in include/PruArmCommon.h) #define COMM_ERROR_OCCURRED 68 // Signals the ARM CPU that an error happened #define COMM_ACTIVE_CHANNELS 72 // How many TDM slots contain useful data -#define COMM_MCASP_CONF_XFMT 76 -#define COMM_MCASP_CONF_ACLKXCTL 80 -#define COMM_MCASP_CONF_AFSXCTL 84 -#define COMM_MCASP_CONF_RFMT 88 +// the order of the following registers has to strictly follow the order of the +// members of McaspRegisters +#define COMM_MCASP_CONF_PDIR 76 +#define COMM_MCASP_CONF_RMASK 80 +#define COMM_MCASP_CONF_RFMT 84 +#define COMM_MCASP_CONF_AFSRCTL 88 #define COMM_MCASP_CONF_ACLKRCTL 92 -#define COMM_MCASP_CONF_AFSRCTL 96 -#define COMM_MCASP_CONF_PDIR 100 +#define COMM_MCASP_CONF_RTDM 96 +#define COMM_MCASP_CONF_XMASK 100 +#define COMM_MCASP_CONF_XFMT 104 +#define COMM_MCASP_CONF_AFSXCTL 108 +#define COMM_MCASP_CONF_ACLKXCTL 112 +#define COMM_MCASP_CONF_XTDM 116 +#define COMM_MCASP_CONF_SRCTLN 120 // 4 bytes, one for each of SRCTL[0]...SRCTL[3] +#define COMM_MCASP_CONF_WFIFOCTL 124 +#define COMM_MCASP_CONF_RFIFOCTL 128 // ARM accesses these memory locations as uint32_t // to avoid duplication and mistakes, we use macros to generate the values for ARM diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 048a504a1..a13551a35 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -474,17 +474,18 @@ DONE: MCASP_REG_WRITE MCASP_AHCLKRCTL, mcasp_ahclkrctl_value MCASP_REG_WRITE MCASP_RTDM, mcasp_rtdm_value MCASP_REG_WRITE MCASP_RINTCTL, mcasp_rintctl_value // Enable receive start of frame interrupt - MCASP_REG_WRITE MCASP_XMASK, mcasp_data_mask // xx bit data transmit + MCASP_REG_WRITE MCASP_RMASK, mcasp_data_mask // xx bit data transmit .endm .macro MCASP_SET_TX -.mparam mcasp_data_format, mcasp_afsxctl_value, mcasp_aclkxctl_value, mcasp_ahclkxctl_value, mcasp_xtdm_value, mcasp_xintctl_value +.mparam mcasp_data_format, mcasp_afsxctl_value, mcasp_aclkxctl_value, mcasp_ahclkxctl_value, mcasp_xtdm_value, mcasp_xintctl_value, mcasp_data_mask MCASP_REG_WRITE MCASP_XFMT, mcasp_data_format // Set data format MCASP_REG_WRITE MCASP_AFSXCTL, mcasp_afsxctl_value // Set transmit frameclock MCASP_REG_WRITE MCASP_ACLKXCTL, mcasp_aclkxctl_value // Set transmit bitclock MCASP_REG_WRITE MCASP_AHCLKXCTL, mcasp_ahclkxctl_value MCASP_REG_WRITE MCASP_XTDM, mcasp_xtdm_value MCASP_REG_WRITE MCASP_XINTCTL, mcasp_xintctl_value + MCASP_REG_WRITE MCASP_XMASK, mcasp_data_mask // xx bit data transmit .endm .macro READ_GPIO_BITS @@ -544,6 +545,24 @@ DONE: AND DEST, DEST, (64-1) .endm +.macro CONFIGURE_FIFO +.mparam fifo_address, reg_value + // The descriptions for WFIFOCTL and RWFIFOCTL seem to indicate that you + // need to set the lower bits first and only then set the enable bit. + // So we mask out the enable bit, write the value, wait a bit for the value + // to be recorded by the McASP, unmask the bit, write again + MOV r27, reg_value + // this has to be r27 (and not r28), or it will be overwritten + // by MCASP_REG_WRITE_EXT + CLR r27, r27, 16 + MCASP_REG_WRITE_EXT fifo_address, r27 + MOV r28, 1000 +WAIT: + SUB r28, r28, 1 + QBNE WAIT, r28, 0 + MCASP_REG_WRITE_EXT fifo_address, reg_value +.endm + .macro COMPUTE_TDM_MASK .mparam reg_io QBEQ DONE, reg_io, 0 @@ -1270,10 +1289,11 @@ SPI_INIT_DONE: // Prepare McASP0 for audio MCASP_REG_WRITE MCASP_GBLCTL, 0 // Disable McASP - MCASP_REG_WRITE_EXT MCASP_WFIFOCTL, 0x1 // Configure FIFOs - MCASP_REG_WRITE_EXT MCASP_RFIFOCTL, 0x1 - MCASP_REG_WRITE_EXT MCASP_WFIFOCTL, 0x10001 // Enable FIFOs - MCASP_REG_WRITE_EXT MCASP_RFIFOCTL, 0x10001 + // Configure FIFOs + LBBO r2, reg_comm_addr, COMM_MCASP_CONF_WFIFOCTL, 4 + CONFIGURE_FIFO MCASP_WFIFOCTL, r2 + LBBO r2, reg_comm_addr, COMM_MCASP_CONF_RFIFOCTL, 4 + CONFIGURE_FIFO MCASP_RFIFOCTL, r2 MCASP_REG_WRITE_EXT MCASP_SRCTL0, 0 // All serialisers off MCASP_REG_WRITE_EXT MCASP_SRCTL1, 0 MCASP_REG_WRITE_EXT MCASP_SRCTL2, 0 @@ -1283,15 +1303,15 @@ SPI_INIT_DONE: MCASP_REG_WRITE MCASP_PWRIDLESYSCONFIG, 0x02 // Power on MCASP_REG_WRITE MCASP_PFUNC, 0x00 // All pins are McASP + // Set pin direction #ifdef DBOX_CAPE LBBO r2, reg_comm_addr, COMM_MCASP_CONF_PDIR, 4 #else // DBOX_CAPE MOV r2, MCASP_OUTPUT_PINS #endif // DBOX_CAPE - MCASP_REG_WRITE MCASP_PDIR, r2 // Set pin direction - MCASP_REG_WRITE MCASP_DLBCTL, 0x00 - MCASP_REG_WRITE MCASP_DITCTL, 0x00 - MCASP_REG_WRITE MCASP_RMASK, MCASP_DATA_MASK // 16 bit data receive + MCASP_REG_WRITE MCASP_PDIR, r2 + MCASP_REG_WRITE MCASP_DLBCTL, 0x00 // disable loopback + MCASP_REG_WRITE MCASP_DITCTL, 0x00A // disable DIT // Check how many channels we have READ_ACTIVE_CHANNELS_INTO_FLAGS @@ -1321,9 +1341,9 @@ MCASP_SET_RX_NOT_CTAG_BEAST: LBBO r1, reg_comm_addr, COMM_MCASP_CONF_RFMT, 4 LBBO r2, reg_comm_addr, COMM_MCASP_CONF_AFSRCTL, 4 LBBO r3, reg_comm_addr, COMM_MCASP_CONF_ACLKRCTL, 4 - GET_NUM_AUDIO_OUT_CHANNELS r4 - COMPUTE_TDM_MASK r4 - MCASP_SET_RX r1, r2, r3, MCASP_AHCLKRCTL_VALUE, r4, MCASP_RINTCTL_VALUE, MCASP_DATA_MASK + LBBO r4, reg_comm_addr, COMM_MCASP_CONF_RTDM, 4 + LBBO r5, reg_comm_addr, COMM_MCASP_CONF_RMASK, 4 + MCASP_SET_RX r1, r2, r3, MCASP_AHCLKRCTL_VALUE, r4, MCASP_RINTCTL_VALUE, r5 QBA MCASP_SET_RX_DONE MCASP_SET_RX_NOT_BELA_TLV32_OR_BELA_MULTI_TLV: @@ -1332,13 +1352,13 @@ MCASP_SET_RX_DONE: // set MCASP TX #ifdef ENABLE_CTAG_FACE IF_NOT_CTAG_FACE_JMP_TO MCASP_SET_TX_NOT_CTAG_FACE - MCASP_SET_TX CTAG_FACE_MCASP_DATA_FORMAT_TX_VALUE, CTAG_FACE_MCASP_AFSXCTL_VALUE, CTAG_FACE_MCASP_ACLKXCTL_VALUE, CTAG_FACE_MCASP_AHCLKXCTL_VALUE, CTAG_FACE_MCASP_XTDM_VALUE, CTAG_FACE_MCASP_XINTCTL_VALUE + MCASP_SET_TX CTAG_FACE_MCASP_DATA_FORMAT_TX_VALUE, CTAG_FACE_MCASP_AFSXCTL_VALUE, CTAG_FACE_MCASP_ACLKXCTL_VALUE, CTAG_FACE_MCASP_AHCLKXCTL_VALUE, CTAG_FACE_MCASP_XTDM_VALUE, CTAG_FACE_MCASP_XINTCTL_VALUE, MCASP_DATA_MASK QBA MCASP_SET_TX_DONE MCASP_SET_TX_NOT_CTAG_FACE: #endif /* ENABLE_CTAG_FACE */ #ifdef ENABLE_CTAG_BEAST IF_NOT_CTAG_BEAST_JMP_TO MCASP_SET_TX_NOT_CTAG_BEAST - MCASP_SET_TX CTAG_BEAST_MCASP_DATA_FORMAT_TX_VALUE, CTAG_BEAST_MCASP_AFSXCTL_VALUE, CTAG_BEAST_MCASP_ACLKXCTL_VALUE, CTAG_BEAST_MCASP_AHCLKXCTL_VALUE, CTAG_BEAST_MCASP_XTDM_VALUE, CTAG_BEAST_MCASP_XINTCTL_VALUE + MCASP_SET_TX CTAG_BEAST_MCASP_DATA_FORMAT_TX_VALUE, CTAG_BEAST_MCASP_AFSXCTL_VALUE, CTAG_BEAST_MCASP_ACLKXCTL_VALUE, CTAG_BEAST_MCASP_AHCLKXCTL_VALUE, CTAG_BEAST_MCASP_XTDM_VALUE, CTAG_BEAST_MCASP_XINTCTL_VALUE, MCASP_DATA_MASK QBA MCASP_SET_TX_DONE MCASP_SET_TX_NOT_CTAG_BEAST: #endif /* ENABLE_CTAG_BEAST */ @@ -1347,16 +1367,31 @@ MCASP_SET_TX_NOT_CTAG_BEAST: LBBO r1, reg_comm_addr, COMM_MCASP_CONF_XFMT, 4 LBBO r2, reg_comm_addr, COMM_MCASP_CONF_AFSXCTL, 4 LBBO r3, reg_comm_addr, COMM_MCASP_CONF_ACLKXCTL, 4 - GET_NUM_AUDIO_OUT_CHANNELS r4 - COMPUTE_TDM_MASK r4 - MCASP_SET_TX r1, r2, r3, MCASP_AHCLKXCTL_VALUE, r4, MCASP_XINTCTL_VALUE + LBBO r4, reg_comm_addr, COMM_MCASP_CONF_XTDM, 4 + LBBO r5, reg_comm_addr, COMM_MCASP_CONF_XMASK, 4 + MCASP_SET_TX r1, r2, r3, MCASP_AHCLKXCTL_VALUE, r4, MCASP_XINTCTL_VALUE, r5 QBA MCASP_SET_TX_DONE MCASP_SET_TX_NOT_BELA_TLV32_OR_BELA_MULTI_TLV: MCASP_SET_TX_DONE: + IF_NOT_CTAG_JMP_TO MCASP_SRCTL_NOT_CTAG MCASP_REG_WRITE_EXT MCASP_SRCTL_R, 0x02 // Set up receive serialiser MCASP_REG_WRITE_EXT MCASP_SRCTL_X, 0x01 // Set up transmit serialiser +MCASP_SRCTL_NOT_CTAG: + IF_NOT_BELA_TLV32_OR_BELA_MULTI_TLV_JMP_TO MCASP_SRCTL_NOT_BELA_TLV32_OR_BELA_MULTI_TLV + LBBO r1, reg_comm_addr, COMM_MCASP_CONF_SRCTLN, 4 + // 4 bytes, one for each of SRCTL[0]...SRCTL[3] + MOV r2, 0 + MOV r2, r1.b0 + MCASP_REG_WRITE_EXT MCASP_SRCTL0, r2 + MOV r2, r1.b1 + MCASP_REG_WRITE_EXT MCASP_SRCTL1, r2 + MOV r2, r1.b2 + MCASP_REG_WRITE_EXT MCASP_SRCTL2, r2 + MOV r2, r1.b3 + MCASP_REG_WRITE_EXT MCASP_SRCTL3, r2 +MCASP_SRCTL_NOT_BELA_TLV32_OR_BELA_MULTI_TLV: MCASP_REG_WRITE MCASP_XSTAT, 0xFF // Clear transmit errors MCASP_REG_WRITE MCASP_RSTAT, 0xFF // Clear receive errors From bfa86880955c9c2d9549e0f0829d89a9bd57da79 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 6 Apr 2020 16:45:20 +0000 Subject: [PATCH 047/148] core: McaspConfig's configuration parameters are now in a McaspConfig::Parameters variable whose fields can be freely set by the user. The registers get now computed all at once when getRegisters() is called. Also fixed rmask/xmask computation. --- core/I2c_Codec.cpp | 42 +++++++++--------------- core/I2c_MultiTLVCodec.cpp | 6 ++-- core/Mcasp.cpp | 64 ++++++++++++++++++++++++------------- core/RTAudio.cpp | 2 +- core/Spi_Codec.cpp | 2 +- include/AudioCodec.h | 2 +- include/I2c_Codec.h | 2 +- include/I2c_MultiTLVCodec.h | 2 +- include/Mcasp.h | 31 +++++++++++++----- include/Spi_Codec.h | 2 +- 10 files changed, 88 insertions(+), 67 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 2bd31751e..004fb9bc9 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -718,7 +718,7 @@ I2c_Codec::~I2c_Codec() stopAudio(); } -const McaspConfig& I2c_Codec::getMcaspConfig() +McaspConfig& I2c_Codec::getMcaspConfig() { /* #define BELA_TLV_MCASP_DATA_FORMAT_TX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits @@ -729,36 +729,24 @@ const McaspConfig& I2c_Codec::getMcaspConfig() #define BELA_TLV_MCASP_AFSRCTL_VALUE 0x100 // 2 Slot I2S, external fsclk, polarity (rising edge), single bit #define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 2) // AHCLKX and AXR2 outputs */ - bool externalSamplingOnRisingEdge = true; - bool wclkIsWord = false; - bool wclkIsInternal = !params.generatesWclk; - bool wclkFalling = false; - uint32_t numSlots; + unsigned int numSlots; if(params.tdmMode) - numSlots = 256 / params.slotSize; // codec is in 256-bit mode + // codec is in 256-bit mode + numSlots = 256 / params.slotSize; else numSlots = 2; + mcaspConfig.params.inChannels = 2; + mcaspConfig.params.outChannels = 2; + mcaspConfig.params.inSerializers = {0}; + mcaspConfig.params.outSerializers = {2}; + mcaspConfig.params.numSlots = numSlots; + mcaspConfig.params.slotSize = params.slotSize; + mcaspConfig.params.bitDelay = params.bitDelay; + mcaspConfig.params.wclkIsInternal = !params.generatesWclk; + mcaspConfig.params.wclkIsWord = false; + mcaspConfig.params.wclkFalling = false; + mcaspConfig.params.externalRisingEdge = true; - int ret = mcaspConfig.setFmt(params.slotSize, params.bitDelay); - if(ret) - fprintf(stderr, "Error while setting FMT\n"); - ret = mcaspConfig.setAclkctl(externalSamplingOnRisingEdge); - if(ret) - fprintf(stderr, "Error while setting ACLKCTL\n"); - ret = mcaspConfig.setAfsctl(numSlots, wclkIsWord, wclkIsInternal, wclkFalling); - if(ret) - fprintf(stderr, "Error while setting AFSCTL\n"); - unsigned char axr = 1 << 2; - ret = mcaspConfig.setPdir(wclkIsInternal, axr); - if(ret) - fprintf(stderr, "Error while setting PDIR\n"); - - ret = mcaspConfig.setInChannels(2, {0}); - if(ret) - fprintf(stderr, "Error while setting input channels\n"); - ret = mcaspConfig.setOutChannels(2, {2}); - if(ret) - fprintf(stderr, "Error while setting output channels\n"); return mcaspConfig; } diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 93ea1a897..1faa7bdd4 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -274,11 +274,11 @@ I2c_MultiTLVCodec::~I2c_MultiTLVCodec() delete masterCodec; } -const McaspConfig& I2c_MultiTLVCodec::getMcaspConfig() +McaspConfig& I2c_MultiTLVCodec::getMcaspConfig() { mc = masterCodec->getMcaspConfig(); - mc.setInChannels(getNumIns(), {0}); - mc.setOutChannels(getNumOuts(), {2}); + mc.params.inChannels = getNumIns(); + mc.params.outChannels = getNumOuts(); return mc; /* // Values below are for 16x 16-bit TDM slots diff --git a/core/Mcasp.cpp b/core/Mcasp.cpp index 0a5c8f387..00e329756 100644 --- a/core/Mcasp.cpp +++ b/core/Mcasp.cpp @@ -1,13 +1,12 @@ #include "../include/Mcasp.h" #include +#include -McaspConfig::McaspConfig() : - regs({0}) +McaspConfig::McaspConfig() { - regs.rmask = regs.xmask = 0xFFFF; } -int McaspConfig::setFmt(unsigned int slotSize, unsigned int bitDelay) +int McaspConfig::setFmt() { struct { unsigned ROT : 3; @@ -20,6 +19,7 @@ int McaspConfig::setFmt(unsigned int slotSize, unsigned int bitDelay) unsigned : 14; } s = {0}; + unsigned int slotSize = params.slotSize; int rotation = 32 - slotSize; //XDATDLY: 0-3h Transmit sync bit delay. @@ -30,7 +30,7 @@ int McaspConfig::setFmt(unsigned int slotSize, unsigned int bitDelay) //2h 2-bit delay. The first transmit data bit, AXRn, occurs two ACLKX cycles //after the transmit frame sync (AFSX). //3h Reserved. - s.DATADLY = bitDelay; + s.DATADLY = params.bitDelay; //15 XRVRS Transmit serial bitstream order. //0 Bitstream is LSB first. No bit reversal is performed in transmit format bit @@ -91,7 +91,7 @@ int McaspConfig::setFmt(unsigned int slotSize, unsigned int bitDelay) //5h Rotate right by 20 bit positions. //6h Rotate right by 24 bit positions. //7h Rotate right by 28 bit positions. - if(rotation & 3) // has to be a multiple of 4 + if(rotation & 3 || rotation < 0) // has to be a multiple of 4 return -1; s.ROT = rotation >> 2; @@ -100,7 +100,7 @@ int McaspConfig::setFmt(unsigned int slotSize, unsigned int bitDelay) return 0; } -int McaspConfig::setAclkctl(bool externalRisingEdge) +int McaspConfig::setAclkctl() { struct { unsigned CLKDIV : 5; @@ -117,7 +117,7 @@ int McaspConfig::setAclkctl(bool externalRisingEdge) // 1 Falling edge. External receiver samples data on the rising edge of the // serial clock, so the transmitter must shift data out on the falling edge of // the serial clock. - s.CLKP = !externalRisingEdge; + s.CLKP = !params.externalRisingEdge; // ASYNC: Transmit/receive operation asynchronous enable bit. // 0 Synchronous. Transmit clock and frame sync provides the source for both @@ -143,7 +143,7 @@ int McaspConfig::setAclkctl(bool externalRisingEdge) return 0; } -int McaspConfig::setAfsctl(unsigned int numSlots, bool wclkIsWord, bool wclkIsInternal, bool wclkFalling) +int McaspConfig::setAfsctl() { struct { unsigned FSP : 1; @@ -161,28 +161,28 @@ int McaspConfig::setAfsctl(unsigned int numSlots, bool wclkIsWord, bool wclkIsIn // 21h-17Fh Reserved. // 180h 384-slot DIT mode. // 181h-1FFh Reserved. - if(numSlots > 32 || numSlots < 2) + if(params.numSlots > 32 || params.numSlots < 2) return 1; - s.MOD = numSlots; + s.MOD = params.numSlots; // FXWID: Transmit frame sync width select bit indicates the width of the // transmit frame sync (AFSX) during its active period. // 0 Single bit. // 1 Single word. - s.FWID = wclkIsWord; + s.FWID = params.wclkIsWord; // FSXM: Transmit frame sync generation select bit. // 0 Externally-generated transmit frame sync. // 1 Internally-generated transmit frame sync. - s.FSM = wclkIsInternal; + s.FSM = params.wclkIsInternal; // FSXP: Transmit frame sync polarity select bit. //0 A rising edge on transmit frame sync (AFSX) indicates the beginning of a frame. //1 A falling edge on transmit frame sync (AFSX) indicates the beginning of a frame. - s.FSP = wclkFalling; + s.FSP = params.wclkFalling; memcpy(®s.afsxctl, &s, sizeof(regs.afsxctl)); regs.afsrctl = regs.afsxctl; return 0; } -int McaspConfig::setPdir(bool wclkIsInternal, unsigned char axr) +int McaspConfig::setPdir() { struct { unsigned AXR : 6; @@ -210,7 +210,7 @@ int McaspConfig::setPdir(bool wclkIsInternal, unsigned char axr) // AFSX: Determines if AFSX pin functions as an input or output. // 0 Pin functions as input. // 1 Pin functions as output. - s.AFSX = wclkIsInternal; + s.AFSX = params.wclkIsInternal; // AHCLKX: Determines if AHCLKX pin functions as an input or output. // 0 Pin functions as input. // 1 Pin functions as output. @@ -226,6 +226,9 @@ int McaspConfig::setPdir(bool wclkIsInternal, unsigned char axr) // AXR[5-0]: Determines if AXRn pin functions as an input or output. // 0 Pin functions as input. // 1 Pin functions as output + uint8_t axr = 0; + for(const auto& n : params.outSerializers) + axr |= (1 << n); s.AXR = axr; memcpy(®s.pdir, &s, sizeof(regs.pdir)); @@ -325,14 +328,29 @@ int McaspConfig::setChannels(unsigned int numChannels, std::vector return ret; } -int McaspConfig::setInChannels(unsigned int numChannels, std::vector serializers) -{ - return setChannels(numChannels, serializers, true); -} - -int McaspConfig::setOutChannels(unsigned int numChannels, std::vector serializers) +McaspRegisters McaspConfig::getRegisters() { - return setChannels(numChannels, serializers, false); + int ret = setFmt(); + if(ret) + fprintf(stderr, "Error while setting FMT\n"); + ret = setAclkctl(); + if(ret) + fprintf(stderr, "Error while setting ACLKCTL\n"); + ret = setAfsctl(); + if(ret) + fprintf(stderr, "Error while setting AFSCTL\n"); + ret = setPdir(); + if(ret) + fprintf(stderr, "Error while setting PDIR\n"); + // individual bytes of regs.srctln are set by setSrctln(), which is + // called by setChannels() + regs.srctln = 0; + ret = setChannels(params.inChannels, params.inSerializers, true); + fprintf(stderr, "Error while setting input channels\n"); + ret = setChannels(params.outChannels, params.outSerializers, false); + fprintf(stderr, "Error while setting output channels\n"); + regs.rmask = regs.xmask = (1 << params.slotSize) - 1; + return regs; } #include diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 457d8d44a..4efe7e456 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -672,7 +672,7 @@ static int startAudioInline(){ } // initialize and run the PRU - if(gPRU->start(gPRUFilename, gAudioCodec->getMcaspConfig().regs)) { + if(gPRU->start(gPRUFilename, gAudioCodec->getMcaspConfig().getRegisters())) { fprintf(stderr, "Error: unable to start PRU from %s\n", gPRUFilename[0] ? "embedded binary" : gPRUFilename); return -1; } diff --git a/core/Spi_Codec.cpp b/core/Spi_Codec.cpp index 9ea9a8239..3b67ce3a6 100644 --- a/core/Spi_Codec.cpp +++ b/core/Spi_Codec.cpp @@ -353,7 +353,7 @@ int Spi_Codec::_spiTransfer(unsigned char* tx_buf, unsigned char* rx_buf, size_t return 0; } -const McaspConfig& Spi_Codec::getMcaspConfig() { +McaspConfig& Spi_Codec::getMcaspConfig() { return mcaspConfig; } diff --git a/include/AudioCodec.h b/include/AudioCodec.h index 01efd1429..87441b4d5 100644 --- a/include/AudioCodec.h +++ b/include/AudioCodec.h @@ -29,5 +29,5 @@ class AudioCodec virtual int setHPVolume(int halfDbSteps) = 0; virtual int disable() = 0; virtual int reset() = 0; - virtual const McaspConfig& getMcaspConfig() = 0; + virtual McaspConfig& getMcaspConfig() = 0; }; diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index 222c1a2bc..502dda675 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -70,7 +70,7 @@ class I2c_Codec : public I2c, public AudioCodec I2c_Codec(int i2cBus, int I2cAddress, CodecType type, bool verbose = false); ~I2c_Codec(); - const McaspConfig& getMcaspConfig(); + McaspConfig& getMcaspConfig(); private: int configureDCRemovalIIR(bool enable); //called by startAudio() int codecType; diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index 3c1b915d6..13ec16350 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -36,7 +36,7 @@ class I2c_MultiTLVCodec : public AudioCodec void debugWriteRegister(int codecNum, int regNum, int value); int debugReadRegister(int codecNum, int regNum); - const McaspConfig& getMcaspConfig(); + McaspConfig& getMcaspConfig(); I2c_MultiTLVCodec(int i2cBus, int i2cAddress, bool verbose = false); ~I2c_MultiTLVCodec(); diff --git a/include/Mcasp.h b/include/Mcasp.h index e90e143d5..9dfd0cfbe 100644 --- a/include/Mcasp.h +++ b/include/Mcasp.h @@ -27,6 +27,20 @@ struct McaspRegisters class McaspConfig { public: + struct Parameters + { + unsigned int inChannels; + unsigned int outChannels; + std::vector inSerializers; + std::vector outSerializers; + unsigned int numSlots; + unsigned int slotSize; + unsigned int bitDelay; + bool wclkIsInternal; + bool wclkIsWord; + bool wclkFalling; + bool externalRisingEdge; + }; typedef enum { SrctlMode_DISABLED = 0, SrctlMode_TX = 1, @@ -38,16 +52,17 @@ class McaspConfig SrctlDrive_HIGH = 3, } SrctlDrive; McaspConfig(); - int setFmt(unsigned int slotSize, unsigned int bitDelay); - int setAclkctl(bool externalRisingEdge); - int setAfsctl(unsigned int numSlots, bool wclkIsWord, bool wclkIsInternal, bool wclkFalling); - int setPdir(bool wclkIsInternal, unsigned char axr); - int setSrctln(unsigned int n, SrctlMode mode, SrctlDrive drive); - int setInChannels(unsigned int numChannels, std::vector serializers); - int setOutChannels(unsigned int numChannels, std::vector serializers); - int setChannels(unsigned int numChannels, std::vector& serializers, bool input); + Parameters params; + McaspRegisters getRegisters(); +private: static uint32_t computeTdm(unsigned int numChannels); static uint32_t computeFifoctl(unsigned int numSerializers); + int setFmt(); + int setAclkctl(); + int setAfsctl(); + int setPdir(); + int setSrctln(unsigned int n, McaspConfig::SrctlMode mode, McaspConfig::SrctlDrive drive); + int setChannels(unsigned int numChannels, std::vector& serializers, bool input); McaspRegisters regs; }; diff --git a/include/Spi_Codec.h b/include/Spi_Codec.h index cdf10ad57..0d2ce7400 100644 --- a/include/Spi_Codec.h +++ b/include/Spi_Codec.h @@ -59,7 +59,7 @@ class Spi_Codec : public AudioCodec { int setHPVolume(int halfDbSteps) {return 0;}; int setPga(float newGain, unsigned short int channel) {return 0;}; int disable() {return 0;}; - const McaspConfig& getMcaspConfig(); + McaspConfig& getMcaspConfig(); private: int _fd_master, _fd_slave; From 52b02b8cd0cb9e11926d6fbb1302e724b370c6d5 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 6 Apr 2020 17:34:22 +0000 Subject: [PATCH 048/148] board_detect: somewhat rationalisesd the enum<->string conversion using a std::map --- core/board_detect.cpp | 79 ++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 53 deletions(-) diff --git a/core/board_detect.cpp b/core/board_detect.cpp index 6c071435e..1e617eb79 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -5,11 +5,23 @@ #include #include #include +#include #include "../include/I2c_Codec.h" #include "../include/Spi_Codec.h" #include "../include/bela_hw_settings.h" #include "../include/board_detect.h" +static const std::map belaHwMap = { + {"NoHardware", BelaHw_NoHw}, + {"Bela", BelaHw_Bela}, + {"BelaMini", BelaHw_BelaMini}, + {"Salt", BelaHw_Salt}, + {"CtagFace", BelaHw_CtagFace}, + {"CtagBeast", BelaHw_CtagBeast}, + {"CtagFaceBela", BelaHw_CtagFaceBela}, + {"CtagBeastBela", BelaHw_CtagBeastBela}, +}; + static const int EEPROM_NUMCHARS = 30; static char eeprom_str[EEPROM_NUMCHARS]; static void read_eeprom(){ @@ -96,62 +108,23 @@ static int detectCtag() BelaHw getBelaHw(std::string board) { - BelaHw hw; - if(board == "Bela") - hw = BelaHw_Bela; - else if(board == "BelaMini") - hw = BelaHw_BelaMini; - else if(board == "Salt") - hw = BelaHw_Salt; - else if(board == "CtagFace") - hw = BelaHw_CtagFace; - else if(board == "CtagBeast") - hw = BelaHw_CtagBeast; - else if(board == "CtagFaceBela") - hw = BelaHw_CtagFaceBela; - else if(board == "CtagBeastBela") - hw = BelaHw_CtagBeastBela; - else if(board == "BelaMiniMultiAudio") - hw = BelaHw_BelaMiniMultiAudio; - else - hw = BelaHw_NoHw; - return hw; + try { + return belaHwMap.at(board); + } catch (std::exception e) { + return BelaHw_NoHw; + } } -std::string getBelaHwName(BelaHw hardware) +std::string getBelaHwName(const BelaHw hardware) { - std::string hwName; - switch(hardware) - { - case BelaHw_Bela: - hwName = "Bela"; - break; - case BelaHw_BelaMini: - hwName = "BelaMini"; - break; - case BelaHw_Salt: - hwName = "Salt"; - break; - case BelaHw_CtagFace: - hwName = "CtagFace"; - break; - case BelaHw_CtagBeast: - hwName = "CtagBeast"; - break; - case BelaHw_CtagFaceBela: - hwName = "CtagFaceBela"; - break; - case BelaHw_CtagBeastBela: - hwName = "CtagBeastBela"; - break; - case BelaHw_BelaMiniMultiAudio: - hwName = "BelaMiniMultiAudio"; - break; - default: - hwName = "NoHardware"; - break; - } - return hwName; + std::string noHw; + for(const auto & hw : belaHwMap) { + if(hw.second == hardware) + return hw.first; + else if (BelaHw_NoHw == hw.second) + noHw = hw.first; + } + return noHw; } static BelaHw parse_config_file(std::string path, std::string searchStr) From f542bca9a6e3cd9400aed0c633639a87e2a05999 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 20 Jul 2020 18:09:26 +0000 Subject: [PATCH 049/148] board_detect: added BelaMiniMultiAudio to the enum --- core/board_detect.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/board_detect.cpp b/core/board_detect.cpp index 1e617eb79..7b7f98b92 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -20,6 +20,7 @@ static const std::map belaHwMap = { {"CtagBeast", BelaHw_CtagBeast}, {"CtagFaceBela", BelaHw_CtagFaceBela}, {"CtagBeastBela", BelaHw_CtagBeastBela}, + {"BelaMiniMultiAudio", BelaHw_BelaMiniMultiAudio}, }; static const int EEPROM_NUMCHARS = 30; From 4a608bbfff3aef68198c8b6622c86240dec0e7cc Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 6 Apr 2020 17:49:58 +0000 Subject: [PATCH 050/148] core: Mcasp: fixed and improved error reporting --- core/Mcasp.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/core/Mcasp.cpp b/core/Mcasp.cpp index 00e329756..4b8e4b4e6 100644 --- a/core/Mcasp.cpp +++ b/core/Mcasp.cpp @@ -332,23 +332,25 @@ McaspRegisters McaspConfig::getRegisters() { int ret = setFmt(); if(ret) - fprintf(stderr, "Error while setting FMT\n"); + fprintf(stderr, "McaspConfig: error while setting FMT\n"); ret = setAclkctl(); if(ret) - fprintf(stderr, "Error while setting ACLKCTL\n"); + fprintf(stderr, "McaspConfig: error while setting ACLKCTL\n"); ret = setAfsctl(); if(ret) - fprintf(stderr, "Error while setting AFSCTL\n"); + fprintf(stderr, "McaspConfig: error while setting AFSCTL\n"); ret = setPdir(); if(ret) - fprintf(stderr, "Error while setting PDIR\n"); + fprintf(stderr, "McaspConfig: error while setting PDIR\n"); // individual bytes of regs.srctln are set by setSrctln(), which is // called by setChannels() regs.srctln = 0; ret = setChannels(params.inChannels, params.inSerializers, true); - fprintf(stderr, "Error while setting input channels\n"); + if(ret) + fprintf(stderr, "McaspConfig: error while setting input channels\n"); ret = setChannels(params.outChannels, params.outSerializers, false); - fprintf(stderr, "Error while setting output channels\n"); + if(ret) + fprintf(stderr, "McaspConfig: error while setting output channels\n"); regs.rmask = regs.xmask = (1 << params.slotSize) - 1; return regs; } From 55cde7ffc6c42674b603a4348fff1fb29411a56d Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 6 Apr 2020 18:03:44 +0000 Subject: [PATCH 051/148] PRU: NOP, renamed ...BELA_MULTI_TLV... to ...BELA_GENERIC_TDM... --- core/PRU.cpp | 2 +- include/PruArmCommon.h | 2 +- pru/pru_rtaudio_irq.p | 20 ++++++++++---------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/PRU.cpp b/core/PRU.cpp index 2366a7ab2..51c228946 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -566,7 +566,7 @@ void PRU::initialisePruCommon(const McaspRegisters& mcaspRegisters) board_flags |= 1 << BOARD_FLAGS_BELA_MINI; break; case BelaHw_BelaMiniMultiAudio: - board_flags |= 1 << BOARD_FLAGS_BELA_MULTI_TLV; + board_flags |= 1 << BOARD_FLAGS_BELA_GENERIC_TDM; break; case BelaHw_CtagFace: case BelaHw_CtagFaceBela: diff --git a/include/PruArmCommon.h b/include/PruArmCommon.h index 977573b62..2a52d157b 100644 --- a/include/PruArmCommon.h +++ b/include/PruArmCommon.h @@ -5,7 +5,7 @@ #define BOARD_FLAGS_BELA_MINI 0 #define BOARD_FLAGS_CTAG_FACE 1 #define BOARD_FLAGS_CTAG_BEAST 2 -#define BOARD_FLAGS_BELA_MULTI_TLV 3 +#define BOARD_FLAGS_BELA_GENERIC_TDM 3 #define PRU_SYSTEM_EVENT_RTDM 20 #define PRU_SYS_EV_MCASP_RX_INTR 54 // mcasp_r_intr_pend diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index a13551a35..fd7648de6 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -14,7 +14,7 @@ //#define ENABLE_CTAG_FACE // enables run-time selection of the CTAG Face codec. //#define ENABLE_CTAG_BEAST // enables run-time selection of the CTAG Beast codecs #define ENABLE_BELA_TLV32 // enables run-time selection of the Bela TLV32 codec -#define ENABLE_BELA_MULTI_TLV32 // enables run-time selection of multiple Bela TLV32 codecs +#define ENABLE_BELA_GENERIC_TDM // enables run-time selection of custom TDM options //#define ENABLE_MUXER // enables run-time selection of the Multiplexer capelet // there are some issues with this code and this codec. // See https://github.com/BelaPlatform/Bela/issues/480 @@ -1159,7 +1159,7 @@ PRU_NUMBER_CHECK_DONE: SET reg_flags, reg_flags, FLAG_BIT_BELA_MINI BELA_MINI_CHECK_DONE: // Find out whether we are on a multi-TLV Bela setup - QBBC BELA_MULTI_TLV_CHECK_DONE, r2, BOARD_FLAGS_BELA_MULTI_TLV + QBBC BELA_MULTI_TLV_CHECK_DONE, r2, BOARD_FLAGS_BELA_GENERIC_TDM SET reg_flags, reg_flags, FLAG_BIT_BELA_MULTI_TLV BELA_MULTI_TLV_CHECK_DONE: // Find out whether we are on CTAG_FACE @@ -1463,7 +1463,7 @@ WRITE_FRAME_NOT_CTAG_BEAST: MCASP_WRITE_TO_DATAPORT 0x00, 4 WRITE_FRAME_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ -#ifdef ENABLE_BELA_MULTI_TLV32 +#ifdef ENABLE_BELA_GENERIC_TDM IF_NOT_BELA_MULTI_TLV_JMP_TO WRITE_FRAME_NOT_MULTI_TLV GET_NUM_AUDIO_OUT_CHANNELS r2 // How many channels? WRITE_FRAME_MULTI_TLV_LOOP: @@ -1472,7 +1472,7 @@ WRITE_FRAME_MULTI_TLV_LOOP: QBNE WRITE_FRAME_MULTI_TLV_LOOP, r2, 0 WRITE_FRAME_NOT_MULTI_TLV: -#endif /* ENABLE_BELA_MULTI_TLV32 */ +#endif /* ENABLE_BELA_GENERIC_TDM */ WRITE_FRAME_DONE: MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 4) // Set RFRST @@ -1709,7 +1709,7 @@ LOAD_AUDIO_FRAME_NOT_CTAG_BEAST: QBA LOAD_AUDIO_FRAME_DONE LOAD_AUDIO_FRAME_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ -#ifdef ENABLE_BELA_MULTI_TLV32 +#ifdef ENABLE_BELA_GENERIC_TDM IF_NOT_BELA_MULTI_TLV_JMP_TO LOAD_AUDIO_FRAME_NOT_MULTI_TLV // Number of bytes to load depends on number of active TDM slots // LBCO/SBCO only support r0 as indicator of number of bytes @@ -1727,7 +1727,7 @@ LOAD_AUDIO_FRAME_MULTI_TLV_LT16CHAN: ADD reg_mcasp_dac_current, reg_mcasp_dac_current, r0.b0 QBA LOAD_AUDIO_FRAME_DONE LOAD_AUDIO_FRAME_NOT_MULTI_TLV: -#endif /* ENABLE_BELA_MULTI_TLV32 */ +#endif /* ENABLE_BELA_GENERIC_TDM */ SEND_ERROR_TO_ARM ARM_ERROR_INVALID_INIT HALT LOAD_AUDIO_FRAME_DONE: @@ -1785,7 +1785,7 @@ IF_NOT_BELA_TLV32_JMP_TO WRITE_AUDIO_FRAME_NOT_BELA_TLV32 QBA WRITE_AUDIO_FRAME_DONE WRITE_AUDIO_FRAME_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ -#ifdef ENABLE_BELA_MULTI_TLV32 +#ifdef ENABLE_BELA_GENERIC_TDM IF_NOT_BELA_MULTI_TLV_JMP_TO WRITE_AUDIO_FRAME_NOT_MULTI_TLV AND r9, r17, r1 LSR r10, r1, 16 @@ -1830,7 +1830,7 @@ IF_NOT_BELA_MULTI_TLV_JMP_TO WRITE_AUDIO_FRAME_NOT_MULTI_TLV WRITE_AUDIO_FRAME_MULTI_TLV_DONE: QBA WRITE_AUDIO_FRAME_DONE WRITE_AUDIO_FRAME_NOT_MULTI_TLV: -#endif /* ENABLE_BELA_MULTI_TLV32 */ +#endif /* ENABLE_BELA_GENERIC_TDM */ WRITE_AUDIO_FRAME_DONE: XIN SCRATCHPAD_ID_BANK0, r0, 72 // load back register states from scratchpad @@ -1953,7 +1953,7 @@ FRAME_READ_NOT_CTAG_BEAST: QBA FRAME_READ_DONE FRAME_READ_NOT_BELA_TLV32: #endif /* ENABLE_BELA_TLV32 */ -#ifdef ENABLE_BELA_MULTI_TLV32 +#ifdef ENABLE_BELA_GENERIC_TDM IF_NOT_BELA_MULTI_TLV_JMP_TO FRAME_READ_NOT_MULTI_TLV GET_NUM_AUDIO_IN_CHANNELS r0 @@ -2015,7 +2015,7 @@ FRAME_READ_MULTI_TLV_STORE: QBA FRAME_READ_DONE FRAME_READ_NOT_MULTI_TLV: -#endif /* ENABLE_BELA_MULTI_TLV32 */ +#endif /* ENABLE_BELA_GENERIC_TDM */ FRAME_READ_DONE: From 98d9394738d2d99668d49c3cf4961e0b78c73bbb Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 6 Apr 2020 18:26:25 +0000 Subject: [PATCH 052/148] core: checking whether a valid codec was initalised, otherwise fail with a clear error message. Improved logging as well --- core/RTAudio.cpp | 15 +++++++++++++-- core/board_detect.cpp | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 4efe7e456..0e98deec4 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -400,6 +400,11 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) belaHw = actualHw; if(gRTAudioVerbose) printf("Hardware to be used: %s\n", getBelaHwName(belaHw).c_str()); + if(BelaHw_NoHw == belaHw) + { + fprintf(stderr, "Error: unrecognized Bela hardware. Is a cape connected?\n"); + return 1; + } // figure out which codec to use and which to disable if several are present and conflicting unsigned int ctags; @@ -421,13 +426,19 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) gDisabledCodec = new Spi_Codec(ctagSpidevGpioCs0, ctagSpidevGpioCs1); } + if(!gAudioCodec) + { + fprintf(stderr, "Error: invalid combinations of selected and available hardware\n"); + return 1; + } + BelaHwConfig cfg = {0}; BelaHwConfigPrivate pcfg; pcfg.activeCodec = gAudioCodec; pcfg.disabledCodec = gDisabledCodec; if(Bela_getHwConfigPrivate(belaHw, &cfg, &pcfg)) { - fprintf(stderr, "Unrecognized Bela hardware: is a cape connected?\n"); + fprintf(stderr, "Error while retrieving hardware settings Bela hardware: is a cape connected?\n"); return 1; } gContext.audioSampleRate = cfg.audioSampleRate; @@ -606,7 +617,7 @@ void audioLoop(void *) pthread_setmode_np(0, PTHREAD_WARNSW, NULL); #endif // XENOMAI_CATCH_MSW if(gRTAudioVerbose) - printf("_________________Audio Thread!\n"); + rt_printf("_________________Audio Thread!\n"); // All systems go. Run the loop; it will end when gShouldStop is set to 1 gPRU->loop(gUserData, gCoreRender, gHighPerformanceMode); diff --git a/core/board_detect.cpp b/core/board_detect.cpp index 7b7f98b92..360e4de83 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -147,7 +147,7 @@ static BelaHw parse_config_file(std::string path, std::string searchStr) if(hw != BelaHw_NoHw) return hw; else - fprintf(stderr, "Unknown BOARD= in %s: %s. Ignoring.\n", path.c_str(), board.c_str()); + fprintf(stderr, "Unknown setting %s= in %s: %s. Ignoring.\n", searchStr.c_str(), path.c_str(), board.c_str()); } } inputFile.close(); From ed83abd9e198d09d0e02a32eacd678ad7875a781 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 6 Apr 2020 19:28:06 +0000 Subject: [PATCH 053/148] core: CodecParams removed unused element --- core/I2c_Codec.cpp | 1 - include/AudioCodec.h | 1 - 2 files changed, 2 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 004fb9bc9..5e7913e28 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -21,7 +21,6 @@ I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, CodecType type, bool isVerbose running(false) { params.slotSize = 16; - params.tdmSlots = 2; params.startingSlot = 0; params.bitDelay = 0; params.dualRate = false; diff --git a/include/AudioCodec.h b/include/AudioCodec.h index 87441b4d5..8dc7e4382 100644 --- a/include/AudioCodec.h +++ b/include/AudioCodec.h @@ -4,7 +4,6 @@ struct AudioCodecParams { unsigned int slotSize; // size of a slot in bits - unsigned int tdmSlots; // how many tdm slots unsigned int startingSlot; // what slot in the TDM frame to place the first channel in unsigned int bitDelay; // additional offset in the TDM frame (in bits) bool dualRate; // whether to run at single or double sampling rate From 950e2cc8926c71bc7e61c832d7a93da9f343c634 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 6 Apr 2020 19:28:38 +0000 Subject: [PATCH 054/148] core: I2c_Codec be a bit more clever about how you count channels --- core/I2c_Codec.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 5e7913e28..c48479f91 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -734,8 +734,8 @@ McaspConfig& I2c_Codec::getMcaspConfig() numSlots = 256 / params.slotSize; else numSlots = 2; - mcaspConfig.params.inChannels = 2; - mcaspConfig.params.outChannels = 2; + mcaspConfig.params.inChannels = getNumIns(); + mcaspConfig.params.outChannels = getNumOuts();; mcaspConfig.params.inSerializers = {0}; mcaspConfig.params.outSerializers = {2}; mcaspConfig.params.numSlots = numSlots; From efb381bc7066cba639778eb2dbeadc7bf93920b4 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 7 Apr 2020 10:19:17 +0000 Subject: [PATCH 055/148] core: Mcasp added dataSize parameter --- core/I2c_Codec.cpp | 1 + core/Mcasp.cpp | 7 ++++--- include/Mcasp.h | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index c48479f91..ba9b2512f 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -740,6 +740,7 @@ McaspConfig& I2c_Codec::getMcaspConfig() mcaspConfig.params.outSerializers = {2}; mcaspConfig.params.numSlots = numSlots; mcaspConfig.params.slotSize = params.slotSize; + mcaspConfig.params.dataSize = params.slotSize; mcaspConfig.params.bitDelay = params.bitDelay; mcaspConfig.params.wclkIsInternal = !params.generatesWclk; mcaspConfig.params.wclkIsWord = false; diff --git a/core/Mcasp.cpp b/core/Mcasp.cpp index 4b8e4b4e6..e22e70b72 100644 --- a/core/Mcasp.cpp +++ b/core/Mcasp.cpp @@ -2,7 +2,8 @@ #include #include -McaspConfig::McaspConfig() +McaspConfig::McaspConfig() : + params({0}) { } @@ -19,8 +20,7 @@ int McaspConfig::setFmt() unsigned : 14; } s = {0}; - unsigned int slotSize = params.slotSize; - int rotation = 32 - slotSize; + int rotation = 32 - params.dataSize; //XDATDLY: 0-3h Transmit sync bit delay. //0 0-bit delay. The first transmit data bit, AXRn, occurs in same ACLKX cycle @@ -69,6 +69,7 @@ int McaspConfig::setFmt() //Dh Slot size is 28 bits. //Eh Reserved. //Fh Slot size is 32 bits. + unsigned int slotSize = params.slotSize; if(slotSize & 3 || slotSize < 8 || slotSize > 32) return -1; s.SSZ = (slotSize) / 2 - 1; diff --git a/include/Mcasp.h b/include/Mcasp.h index 9dfd0cfbe..d21ee6ebe 100644 --- a/include/Mcasp.h +++ b/include/Mcasp.h @@ -35,6 +35,7 @@ class McaspConfig std::vector outSerializers; unsigned int numSlots; unsigned int slotSize; + unsigned int dataSize; unsigned int bitDelay; bool wclkIsInternal; bool wclkIsWord; From 3e11db3960230c730ab5451e3e24d0b0947870a5 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 7 Apr 2020 11:00:47 +0000 Subject: [PATCH 056/148] core: I2c_Codec is ready to be inherited from --- include/I2c_Codec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index 502dda675..7e849c020 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -71,7 +71,7 @@ class I2c_Codec : public I2c, public AudioCodec ~I2c_Codec(); McaspConfig& getMcaspConfig(); -private: +protected: int configureDCRemovalIIR(bool enable); //called by startAudio() int codecType; int dacVolumeHalfDbs; From 2fd9df8935c9f9e5813fd32c7cbf9f62e3126594 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 27 Mar 2020 19:27:13 +0000 Subject: [PATCH 057/148] core: added generic multi-tdm codec that uses a Tlv320AIC104 as master and then arbitrary tdm channel counts/serializers --- core/I2c_MultiTdmCodec.cpp | 33 +++++++++++++++++++++++++++++++++ core/PRU.cpp | 3 +++ core/RTAudio.cpp | 4 ++++ core/board_detect.cpp | 4 ++++ include/Bela.h | 1 + include/I2c_MultiTdmCodec.h | 10 ++++++++++ 6 files changed, 55 insertions(+) create mode 100644 core/I2c_MultiTdmCodec.cpp create mode 100644 include/I2c_MultiTdmCodec.h diff --git a/core/I2c_MultiTdmCodec.cpp b/core/I2c_MultiTdmCodec.cpp new file mode 100644 index 000000000..4d94aeceb --- /dev/null +++ b/core/I2c_MultiTdmCodec.cpp @@ -0,0 +1,33 @@ +#include "../include/I2c_MultiTdmCodec.h" + +I2c_MultiTdmCodec::I2c_MultiTdmCodec(int i2cBus, int i2cAddress, bool isVerbose /*= false*/) : + I2c_Codec(i2cBus, i2cAddress, CodecType::TLV320AIC3104, isVerbose) +{ + params.slotSize = 32; + params.tdmMode = true; + params.startingSlot = 0; + params.bitDelay = 1; + params.dualRate = false; + params.generatesBclk = true; + params.generatesWclk = true; +} + +McaspConfig& I2c_MultiTdmCodec::getMcaspConfig() +{ + mcaspConfig = I2c_Codec::getMcaspConfig(); + mcaspConfig.params.dataSize = 16; + mcaspConfig.params.inChannels = getNumIns(); + mcaspConfig.params.outChannels = getNumOuts(); + mcaspConfig.params.outSerializers = {1, 2}; + return mcaspConfig; +} + +unsigned int I2c_MultiTdmCodec::getNumIns() +{ + return 2; +} + +unsigned int I2c_MultiTdmCodec::getNumOuts() +{ + return 4; +} diff --git a/core/PRU.cpp b/core/PRU.cpp index 51c228946..c066cf830 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -565,6 +565,7 @@ void PRU::initialisePruCommon(const McaspRegisters& mcaspRegisters) case BelaHw_BelaMini: board_flags |= 1 << BOARD_FLAGS_BELA_MINI; break; + case BelaHw_BelaMiniMultiTdm: case BelaHw_BelaMiniMultiAudio: board_flags |= 1 << BOARD_FLAGS_BELA_GENERIC_TDM; break; @@ -664,6 +665,8 @@ int PRU::start(char * const filename, const McaspRegisters& mcaspRegisters) break; case BelaHw_BelaMiniMultiAudio: //nobreak + case BelaHw_BelaMiniMultiTdm: + //nobreak case BelaHw_CtagFace: //nobreak case BelaHw_CtagBeast: diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 0e98deec4..a0b599f9a 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -53,6 +53,7 @@ #include "../include/I2c_Codec.h" #include "../include/Spi_Codec.h" #include "../include/I2c_MultiTLVCodec.h" +#include "../include/I2c_MultiTdmCodec.h" #include "../include/GPIOcontrol.h" extern "C" void enable_runfast(); extern "C" void disable_runfast(); @@ -419,6 +420,8 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) } else if(belaHw == BelaHw_BelaMiniMultiAudio) gAudioCodec = new I2c_MultiTLVCodec(codecI2cBus, codecI2cAddress, gRTAudioVerbose); + else if(belaHw == BelaHw_BelaMiniMultiTdm) + gAudioCodec = new I2c_MultiTdmCodec(codecI2cBus, codecI2cAddress, gRTAudioVerbose); else if(Bela_hwContains(belaHw, Tlv320aic3104)) { gAudioCodec = new I2c_Codec(codecI2cBus, codecI2cAddress, I2c_Codec::TLV320AIC3104, gRTAudioVerbose); @@ -458,6 +461,7 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) case BelaHw_Salt: fifoFactor = settings->periodSize / 128; break; + case BelaHw_BelaMiniMultiTdm: case BelaHw_BelaMiniMultiAudio: //TODO: we are assuming 6 in / 6 out //nobreak diff --git a/core/board_detect.cpp b/core/board_detect.cpp index 360e4de83..21b0a3343 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -21,6 +21,7 @@ static const std::map belaHwMap = { {"CtagFaceBela", BelaHw_CtagFaceBela}, {"CtagBeastBela", BelaHw_CtagBeastBela}, {"BelaMiniMultiAudio", BelaHw_BelaMiniMultiAudio}, + {"BelaMiniMultiTdm", BelaHw_BelaMiniMultiTdm}, }; static const int EEPROM_NUMCHARS = 30; @@ -255,6 +256,8 @@ bool Bela_checkHwCompatibility(BelaHw userHw, BelaHw detectedHw) return true; else if (userHw == BelaHw_BelaMiniMultiAudio && Bela_hwContains(detectedHw, BelaMiniCape)) return true; + else if (userHw == BelaHw_BelaMiniMultiTdm && Bela_hwContains(detectedHw, BelaMiniCape)) + return true; return false; } @@ -276,6 +279,7 @@ unsigned int Bela_hwContains(const BelaHw hw, const BelaHwComponent::Component c switch(hw) { case BelaHw_BelaMini: case BelaHw_BelaMiniMultiAudio: + case BelaHw_BelaMiniMultiTdm: return 1; default: return 0; diff --git a/include/Bela.h b/include/Bela.h index d2d1c8cc1..017b2ea85 100644 --- a/include/Bela.h +++ b/include/Bela.h @@ -89,6 +89,7 @@ typedef enum BelaHw_CtagFaceBela, BelaHw_CtagBeastBela, BelaHw_BelaMiniMultiAudio, + BelaHw_BelaMiniMultiTdm, } BelaHw; typedef struct _BelaHwConfig diff --git a/include/I2c_MultiTdmCodec.h b/include/I2c_MultiTdmCodec.h new file mode 100644 index 000000000..240024fd6 --- /dev/null +++ b/include/I2c_MultiTdmCodec.h @@ -0,0 +1,10 @@ +#include "I2c_Codec.h" + +class I2c_MultiTdmCodec : public I2c_Codec +{ +public: + I2c_MultiTdmCodec(int i2cBus, int i2cAddress, bool isVerbose = false); + unsigned int getNumIns() override; + unsigned int getNumOuts() override; + McaspConfig& getMcaspConfig() override; +}; From 8b992a03fc126b902ee139f35cfd1fef722e95d6 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Thu, 9 Apr 2020 08:56:24 +0000 Subject: [PATCH 058/148] core: added codec-mode command line option which allows to pass a codec-specific string to the codec initialization --- core/I2c_Codec.cpp | 28 ++++++++++++++++++++++++++-- core/RTAudio.cpp | 4 +++- core/RTAudioCommandLine.cpp | 11 ++++++++++- include/AudioCodec.h | 2 ++ include/Bela.h | 7 +++++-- include/I2c_Codec.h | 8 ++++++++ 6 files changed, 54 insertions(+), 6 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index ba9b2512f..4f5d48ec9 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -17,8 +17,9 @@ #define TLV320_DSP_MODE I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, CodecType type, bool isVerbose /*= false*/) -: codecType(type), dacVolumeHalfDbs(0), adcVolumeHalfDbs(0), hpVolumeHalfDbs(0), -running(false) +: codecType(type), dacVolumeHalfDbs(0), adcVolumeHalfDbs(0), hpVolumeHalfDbs(0) + , running(false) + , mode(InitMode_init) { params.slotSize = 16; params.startingSlot = 0; @@ -33,6 +34,8 @@ running(false) // This method initialises the audio codec to its default state int I2c_Codec::initCodec() { + if(InitMode_noInit == mode) + return 0; // Write the reset register of the codec if(writeRegister(0x01, 0x80)) // Software reset register { @@ -50,6 +53,8 @@ int I2c_Codec::initCodec() // See the TLV320AIC3106 datasheet for full details of the registers int I2c_Codec::startAudio(int dummy) { + if(InitMode_noInit == mode) + return 0; // As a best-practice it's safer not to assume the implementer has issued initCodec() // or has not otherwise modified codec registers since that call. // Explicit Switch to config register page 0: @@ -596,6 +601,8 @@ int I2c_Codec::enableLineOut(bool enable) // This tells the codec to stop generating audio and mute the outputs int I2c_Codec::stopAudio() { + if(InitMode_noInit == mode || InitMode_noDeinit == mode) + return 0; if(writeDACVolumeRegisters(true)) // Mute the DACs return 1; if(writeADCVolumeRegisters(true)) // Mute the ADCs @@ -789,3 +796,20 @@ int I2c_Codec::setParameters(AudioCodecParams& codecParams) } return ret; } + + +int I2c_Codec::setMode(std::string parameter) +{ + if("init" == parameter) + mode = InitMode_init; + else if("noDeinit" == parameter) + mode = InitMode_noDeinit; + else if("noInit" == parameter) + mode = InitMode_noInit; + else { + mode = InitMode_init; + return 1; + } + verbose && printf("Codec mode: %d (%s)\n", mode, parameter.c_str()); + return 0; +} diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index a0b599f9a..e2d0bf83e 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -428,12 +428,14 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) if(Bela_hwContains(actualHw, CtagCape)) gDisabledCodec = new Spi_Codec(ctagSpidevGpioCs0, ctagSpidevGpioCs1); } - + if(!gAudioCodec) { fprintf(stderr, "Error: invalid combinations of selected and available hardware\n"); return 1; } + if(settings->codecMode) + gAudioCodec->setMode(settings->codecMode); BelaHwConfig cfg = {0}; BelaHwConfigPrivate pcfg; diff --git a/core/RTAudioCommandLine.cpp b/core/RTAudioCommandLine.cpp index 88acc754c..b4848b864 100644 --- a/core/RTAudioCommandLine.cpp +++ b/core/RTAudioCommandLine.cpp @@ -20,6 +20,7 @@ #define OPT_UNIFORM_SAMPLE_RATE 1007 #define OPT_HIGH_PERFORMANCE_MODE 1008 #define OPT_BOARD 1009 +#define OPT_CODEC_MODE 1010 // whether it's the first time that Bela_getopt_long is run static bool gFirstRun = 1; @@ -52,6 +53,7 @@ struct option gDefaultLongOptions[] = {"high-performance-mode", 0, NULL, OPT_HIGH_PERFORMANCE_MODE}, {"uniform-sample-rate", 0, NULL, OPT_UNIFORM_SAMPLE_RATE}, {"board", 1, NULL, OPT_BOARD}, + {"codec-mode", 1, NULL, OPT_CODEC_MODE}, {NULL, 0, NULL, 0} }; @@ -65,12 +67,15 @@ BelaInitSettings* Bela_InitSettings_alloc() void Bela_InitSettings_free(BelaInitSettings* settings) { + free(settings->codecMode); free(settings); } // This function sets the default settings for the BelaInitSettings structure void Bela_defaultSettings(BelaInitSettings *settings) { + memset(settings, 0, sizeof(*settings)); + // Set default values for settings settings->periodSize = 16; settings->useAnalog = 1; @@ -317,11 +322,14 @@ int Bela_getopt_long(int argc, char * const argv[], const char *customShortOptio break; case OPT_UNIFORM_SAMPLE_RATE: settings->uniformSampleRate = 1; - printf("Uniform sample rate\n"); break; case OPT_BOARD: settings->board = getBelaHw(std::string(optarg)); break; + case OPT_CODEC_MODE: + settings->codecMode = new char[strlen(optarg) + 1]; + strcpy(settings->codecMode, optarg); + break; case '?': default: return c; @@ -358,6 +366,7 @@ void Bela_usage() std::cerr << " --high-performance-mode Gives more CPU to the Bela process. The system may become unresponsive and you will have to use the button on the Bela cape when you want to stop it.\n"; std::cerr << " --uniform-sample-rate Internally resample the analog channels so that they match the audio sample rate\n"; std::cerr << " --board val: Select a different board to work with\n"; + std::cerr << " --codec-mode val: A codec-specific string representing an intialisation parameter\n"; std::cerr << " --verbose [-v]: Enable verbose logging information\n"; } diff --git a/include/AudioCodec.h b/include/AudioCodec.h index 8dc7e4382..b275639a9 100644 --- a/include/AudioCodec.h +++ b/include/AudioCodec.h @@ -1,5 +1,6 @@ #pragma once #include +#include #include "Mcasp.h" struct AudioCodecParams { @@ -28,5 +29,6 @@ class AudioCodec virtual int setHPVolume(int halfDbSteps) = 0; virtual int disable() = 0; virtual int reset() = 0; + virtual int setMode(std::string parameter) {return 0;}; virtual McaspConfig& getMcaspConfig() = 0; }; diff --git a/include/Bela.h b/include/Bela.h index 017b2ea85..83c900507 100644 --- a/include/Bela.h +++ b/include/Bela.h @@ -32,7 +32,9 @@ // Version history / changelog: // 1.10.0 -// - added parameter to Bela_detectHw(), and associated typedef. Added more values to the BelaHw enum. +// - added parameter to Bela_detectHw(), and associated typedef +// - added more values to the BelaHw enum +// - added codecMode to BelaInitSettings // 1.9.0 // - added Bela_HwConfig_{new,delete} // 1.8.0 @@ -488,7 +490,8 @@ typedef struct { /// Pointer to an optional function to be called when the audio thread is done. /// This function is called from the audio thread itself just before it returns. void (*audioThreadDone)(BelaContext*, void*); - int unused1; + /// A codec-specific intialisation parameter + char* codecMode; char unused2[MAX_UNUSED2_LENGTH]; /// User selected board to work with (as opposed to detected hardware). diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index 7e849c020..936e107b9 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -71,6 +71,7 @@ class I2c_Codec : public I2c, public AudioCodec ~I2c_Codec(); McaspConfig& getMcaspConfig(); + int setMode(std::string mode); protected: int configureDCRemovalIIR(bool enable); //called by startAudio() int codecType; @@ -82,4 +83,11 @@ class I2c_Codec : public I2c, public AudioCodec bool running; bool verbose; bool hpEnabled; + typedef enum + { + InitMode_init = 0, + InitMode_noDeinit = 1, + InitMode_noInit = 2, + } InitMode; + InitMode mode; }; From c92e612ae75cdd0a0860da4a0855631c6b3be06f Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Thu, 9 Apr 2020 11:12:22 +0000 Subject: [PATCH 059/148] core: I2c_Codec more accurate parameter calculation for the PLL (previous version was giving out of spec values) --- core/I2c_Codec.cpp | 97 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 83 insertions(+), 14 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 4f5d48ec9..4901ce5be 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -13,6 +13,8 @@ */ #include "../include/I2c_Codec.h" +#include +#include #define TLV320_DSP_MODE @@ -66,16 +68,6 @@ int I2c_Codec::startAudio(int dummy) return 1; if(params.generatesBclk) { - // The sampling frequency is given as f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P) - // The master clock PLLCLK_IN is 12MHz - // K can be varied in intervals of resolution of 0.0001 up to 63.9999 - // using P=8 and R=1 gives a resolution of 0.0732421875Hz ( 0.000166% at 44.1kHz) - // to obtain Fs=44100 we need to have K=60.2112 - - if(setPllP(8)) - return 1; - if(setPllR(1)) - return 1; if(setAudioSamplingRate(44100)) //this will automatically find and set K for the given P and R so that Fs=44100 return 1; } @@ -392,11 +384,88 @@ int I2c_Codec::setPllR(unsigned int r){ pllR = r; return 0; } + int I2c_Codec::setAudioSamplingRate(float newSamplingRate){ - long int PLLCLK_IN=12000000; - // f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P) - float k = ((double)(newSamplingRate * pllP * 2048.0f/(float)pllR)) / PLLCLK_IN ; - return (setPllK(k)); + double MHz = 1000000; + long int PLLCLK_IN = 12 * MHz; + + // From the TLV3201AIC3104 datasheet, 10.3.3.1 Audio Clock Generation + // The sampling frequency is given as f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P) + // The master clock PLLCLK_IN is 12MHz + // K is J.D and can be varied in intervals of resolution of 0.0001 up to 63.9999 + + // NOTE: This code does not account for the special case where D = 0 + // which has fewer constrains (useful for clock values such as 2.8224 + // and multiples for 44.1kHz and values such as 1.024MHz and multiples + // for 48kHz (see Table 1. Typical MCLK Rates) + + //When the PLL is enabled and D ≠ 0000, the following conditions must be satisfied to meet specified + //performance: + //constraint 1: R = 1 + unsigned int R = 1; + //constraint 2: 10 MHz ≤ PLLCLK_IN/P ≤ 20 MHz + unsigned int Pmin = 1; + unsigned int Pmax = 8; + while(PLLCLK_IN / Pmin > 20*MHz && Pmin <= Pmax) + ++Pmin; + while(PLLCLK_IN / Pmax < 10*MHz && Pmin <= Pmax) + --Pmax; + //constraint 3: 4 ≤ J ≤ 11 (remember that K = J.D) + double Kmin = 4; + double Kmax = 11.9999; + struct PllSettings { + unsigned int P; + unsigned int R; + double K; + double Fs; + }; + std::vector settings; + for(unsigned int P = Pmin; P <= Pmax; ++P) + { + //constraint 4: 80 MHz ≤ PLLCLK_IN × K × R/P ≤ 110 MHz + double localKmin = 80*MHz * P / (PLLCLK_IN * R); + double localKmax = 110*MHz * P / (PLLCLK_IN * R); + localKmin = std::max(localKmin, Kmin); + localKmax = std::min(localKmax, Kmax); + // round the Ks up and down to a value with only 4 decimals + localKmin = ((unsigned int)(localKmin * 10000 + 1)) / 10000.0; + localKmax = ((unsigned int)(localKmax * 10000)) / 10000.0; + if(localKmin < localKmax) + { + // constrains are met, see if we can find a valid combination of settings + // f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P) + // solve for K and check that it is in the valid range + double K = (newSamplingRate * P * 2048.0/R) / (double)PLLCLK_IN; + // round K to 4 decimals + K = ((unsigned int)(K * 10000 + 0.5)) / 10000.0; + if(K >= localKmin && K <= localKmax) + { + double Fs = (PLLCLK_IN * K * R)/(2048 * P); + settings.push_back({.P = P, .R = R, .K = K, .Fs = Fs}); + } + } + } + if(0 == settings.size()) { + fprintf(stderr, "I2c_Codec: error, no valid PLL settings found\n"); + return 1; + } + // find the settings that minimise the Fs error + PllSettings optimalSettings; + double error = std::numeric_limits::max(); + for(auto & s : settings) { + double newError = s.Fs - newSamplingRate; + if(newError < error) { + error = newError; + optimalSettings = s; + } + } + + // The sampling frequency is given as f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P) + if(setPllP(optimalSettings.P)) + return 1; + if(setPllR(optimalSettings.R)) + return 1; + return (setPllK(optimalSettings.K)); } From 3080097c72ad2132511f5be9cddf9ac10ce22d0d Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Thu, 9 Apr 2020 16:37:00 +0000 Subject: [PATCH 060/148] core: allow the codec driver to set Ahclkctl in the Mcasp --- core/I2c_Codec.cpp | 21 ++++++++----- core/Mcasp.cpp | 71 +++++++++++++++++++++++++++++++++++++++++- include/AudioCodec.h | 1 + include/I2c_Codec.h | 3 +- include/Mcasp.h | 9 +++++- include/PruArmCommon.h | 26 +++++++--------- pru/pru_rtaudio_irq.p | 14 +++++---- 7 files changed, 114 insertions(+), 31 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 4901ce5be..21ba2a9ba 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -13,7 +13,7 @@ */ #include "../include/I2c_Codec.h" -#include +#include #include #define TLV320_DSP_MODE @@ -30,6 +30,7 @@ I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, CodecType type, bool isVerbose params.tdmMode = false; params.generatesBclk = true; params.generatesWclk = true; + params.mclk = mcaspConfig.getValidAhclk(24000000); initI2C_RW(i2cBus, i2cAddress, -1); } @@ -68,7 +69,7 @@ int I2c_Codec::startAudio(int dummy) return 1; if(params.generatesBclk) { - if(setAudioSamplingRate(44100)) //this will automatically find and set K for the given P and R so that Fs=44100 + if(setAudioSamplingRate(44100)) return 1; } else { @@ -387,7 +388,7 @@ int I2c_Codec::setPllR(unsigned int r){ int I2c_Codec::setAudioSamplingRate(float newSamplingRate){ double MHz = 1000000; - long int PLLCLK_IN = 12 * MHz; + double PLLCLK_IN = params.mclk; // From the TLV3201AIC3104 datasheet, 10.3.3.1 Audio Clock Generation // The sampling frequency is given as f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P) @@ -453,7 +454,7 @@ int I2c_Codec::setAudioSamplingRate(float newSamplingRate){ PllSettings optimalSettings; double error = std::numeric_limits::max(); for(auto & s : settings) { - double newError = s.Fs - newSamplingRate; + double newError = std::abs(s.Fs - newSamplingRate); if(newError < error) { error = newError; optimalSettings = s; @@ -489,9 +490,9 @@ float I2c_Codec::getPllK(){ } float I2c_Codec::getAudioSamplingRate(){ - long int PLLCLK_IN=12000000; + double PLLCLK_IN = params.mclk; // f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P) - float fs = (PLLCLK_IN/2048.0f) * getPllK()*getPllR()/(float)getPllP(); + float fs = (PLLCLK_IN/2048.0) * getPllK()*getPllR()/(float)getPllP(); return fs; } @@ -818,6 +819,8 @@ McaspConfig& I2c_Codec::getMcaspConfig() mcaspConfig.params.slotSize = params.slotSize; mcaspConfig.params.dataSize = params.slotSize; mcaspConfig.params.bitDelay = params.bitDelay; + mcaspConfig.params.ahclkIsInternal = true; + mcaspConfig.params.ahclkFreq = params.mclk; mcaspConfig.params.wclkIsInternal = !params.generatesWclk; mcaspConfig.params.wclkIsWord = false; mcaspConfig.params.wclkFalling = false; @@ -841,7 +844,7 @@ float I2c_Codec::getSampleRate() { return 44100; } -int I2c_Codec::setParameters(AudioCodecParams& codecParams) +int I2c_Codec::setParameters(const AudioCodecParams& codecParams) { params = codecParams; int ret = 0; @@ -866,6 +869,10 @@ int I2c_Codec::setParameters(AudioCodecParams& codecParams) return ret; } +AudioCodecParams I2c_Codec::getParameters() +{ + return params; +} int I2c_Codec::setMode(std::string parameter) { diff --git a/core/Mcasp.cpp b/core/Mcasp.cpp index e22e70b72..1ce4f8a7a 100644 --- a/core/Mcasp.cpp +++ b/core/Mcasp.cpp @@ -1,12 +1,34 @@ #include "../include/Mcasp.h" #include #include +#include +#include McaspConfig::McaspConfig() : - params({0}) + params({.auxClkIn = 24000000}) { } +double McaspConfig::getValidAhclk(double desiredClk, unsigned int* outDiv) +{ + double error = std::numeric_limits::max(); + unsigned int div; + // search for a local minimum in the error + for(div = 1; div <= 4096; ++div) + { + double newError = std::abs(params.auxClkIn / div - desiredClk); + if(newError < error) + error = newError; + else { + --div; + break; + } + } + if(outDiv) + *outDiv = div; + return params.auxClkIn/div; +} + int McaspConfig::setFmt() { struct { @@ -183,6 +205,50 @@ int McaspConfig::setAfsctl() return 0; } +int McaspConfig::setAhclkctl() +{ + struct { + unsigned HCLKDIV : 12; + unsigned : 2; + unsigned HCLKP : 1; + unsigned HCLKM : 1; + unsigned : 16; + } s = {0}; +// HCLKXM: Transmit high-frequency clock source bit. +// 0 External transmit high-frequency clock source from AHCLKX pin. +// 1 Internal transmit high-frequency clock source from output of programmable +// high clock divider. + s.HCLKM = params.ahclkIsInternal; +// HCLKXP: Transmit bitstream high-frequency clock polarity select bit. +// 0 AHCLKX is not inverted before programmable bit clock divider. In the +// special case where the transmit bit clock (ACLKX) is internally generated +// and the programmable bit clock divider is set to divide-by-1 (CLKXDIV = 0 in +// ACLKXCTL), AHCLKX is directly passed through to the ACLKX pin. +// 1 AHCLKX is inverted before programmable bit clock divider. In the special +// case where the transmit bit clock (ACLKX) is internally generated and the +// programmable bit clock divider is set to divideby-1 (CLKXDIV = 0 in +// ACLKXCTL), AHCLKX is directly passed through to the ACLKX pin. + s.HCLKP = 0; +// HCLKXDIV: 0-FFFh Transmit high-frequency clock divide ratio bits determine the divide-down ratio from AUXCLK to +// AHCLKX. +// 0 Divide-by-1. +// 1h Divide-by-2. +// 2h-FFFh Divide-by-3 to divide-by-4096. + unsigned int hclkdiv; + if(params.ahclkIsInternal) + { + unsigned int div; + getValidAhclk(params.ahclkFreq, &div); + hclkdiv = div - 1; + } else { + hclkdiv = 0; + } + s.HCLKDIV = hclkdiv; + memcpy(®s.ahclkxctl, &s, sizeof(regs.ahclkxctl)); + regs.ahclkrctl = regs.ahclkxctl; + return 0; +} + int McaspConfig::setPdir() { struct { @@ -337,6 +403,9 @@ McaspRegisters McaspConfig::getRegisters() ret = setAclkctl(); if(ret) fprintf(stderr, "McaspConfig: error while setting ACLKCTL\n"); + ret = setAhclkctl(); + if(ret) + fprintf(stderr, "McaspConfig: error while setting AHCLKCTL\n"); ret = setAfsctl(); if(ret) fprintf(stderr, "McaspConfig: error while setting AFSCTL\n"); diff --git a/include/AudioCodec.h b/include/AudioCodec.h index b275639a9..a454191ce 100644 --- a/include/AudioCodec.h +++ b/include/AudioCodec.h @@ -7,6 +7,7 @@ struct AudioCodecParams { unsigned int slotSize; // size of a slot in bits unsigned int startingSlot; // what slot in the TDM frame to place the first channel in unsigned int bitDelay; // additional offset in the TDM frame (in bits) + double mclk; // frequency of the master clock passed to the codec bool dualRate; // whether to run at single or double sampling rate bool tdmMode; // whether to use TDM rather than DSP mode bool generatesBclk; // whether the codec generates the bit clock diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index 936e107b9..cf9332ea1 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -33,7 +33,8 @@ class I2c_Codec : public I2c, public AudioCodec int readRegister(unsigned int reg); int initCodec(); - int setParameters(AudioCodecParams& codecParams); + int setParameters(const AudioCodecParams& codecParams); + AudioCodecParams getParameters(); int startAudio(int dummy); int stopAudio(); unsigned int getNumIns(); diff --git a/include/Mcasp.h b/include/Mcasp.h index d21ee6ebe..25136efb4 100644 --- a/include/Mcasp.h +++ b/include/Mcasp.h @@ -13,11 +13,13 @@ struct McaspRegisters uint32_t rfmt; uint32_t afsrctl; uint32_t aclkrctl; + uint32_t ahclkrctl; uint32_t rtdm; uint32_t xmask; uint32_t xfmt; uint32_t afsxctl; uint32_t aclkxctl; + uint32_t ahclkxctl; uint32_t xtdm; uint32_t srctln; uint32_t wfifoctl; @@ -37,6 +39,9 @@ class McaspConfig unsigned int slotSize; unsigned int dataSize; unsigned int bitDelay; + double auxClkIn; + double ahclkFreq; + bool ahclkIsInternal; bool wclkIsInternal; bool wclkIsWord; bool wclkFalling; @@ -52,6 +57,7 @@ class McaspConfig SrctlDrive_LOW = 2, SrctlDrive_HIGH = 3, } SrctlDrive; + double getValidAhclk(double desiredClock, unsigned int* outDiv = nullptr); McaspConfig(); Parameters params; McaspRegisters getRegisters(); @@ -59,8 +65,9 @@ class McaspConfig static uint32_t computeTdm(unsigned int numChannels); static uint32_t computeFifoctl(unsigned int numSerializers); int setFmt(); - int setAclkctl(); int setAfsctl(); + int setAclkctl(); + int setAhclkctl(); int setPdir(); int setSrctln(unsigned int n, McaspConfig::SrctlMode mode, McaspConfig::SrctlDrive drive); int setChannels(unsigned int numChannels, std::vector& serializers, bool input); diff --git a/include/PruArmCommon.h b/include/PruArmCommon.h index 2a52d157b..107e7bae2 100644 --- a/include/PruArmCommon.h +++ b/include/PruArmCommon.h @@ -46,15 +46,17 @@ #define COMM_MCASP_CONF_RFMT 84 #define COMM_MCASP_CONF_AFSRCTL 88 #define COMM_MCASP_CONF_ACLKRCTL 92 -#define COMM_MCASP_CONF_RTDM 96 -#define COMM_MCASP_CONF_XMASK 100 -#define COMM_MCASP_CONF_XFMT 104 -#define COMM_MCASP_CONF_AFSXCTL 108 -#define COMM_MCASP_CONF_ACLKXCTL 112 -#define COMM_MCASP_CONF_XTDM 116 -#define COMM_MCASP_CONF_SRCTLN 120 // 4 bytes, one for each of SRCTL[0]...SRCTL[3] -#define COMM_MCASP_CONF_WFIFOCTL 124 -#define COMM_MCASP_CONF_RFIFOCTL 128 +#define COMM_MCASP_CONF_AHCLKRCTL 96 +#define COMM_MCASP_CONF_RTDM 100 +#define COMM_MCASP_CONF_XMASK 104 +#define COMM_MCASP_CONF_XFMT 108 +#define COMM_MCASP_CONF_AFSXCTL 112 +#define COMM_MCASP_CONF_ACLKXCTL 116 +#define COMM_MCASP_CONF_AHCLKXCTL 120 +#define COMM_MCASP_CONF_XTDM 124 +#define COMM_MCASP_CONF_SRCTLN 128 // 4 bytes, one for each of SRCTL[0]...SRCTL[3] +#define COMM_MCASP_CONF_WFIFOCTL 132 +#define COMM_MCASP_CONF_RFIFOCTL 136 // ARM accesses these memory locations as uint32_t // to avoid duplication and mistakes, we use macros to generate the values for ARM @@ -83,12 +85,6 @@ ENUM(COMM_BUFFER_SPI_FRAMES) ENUM(COMM_BOARD_FLAGS) ENUM(COMM_ERROR_OCCURRED) ENUM(COMM_ACTIVE_CHANNELS) -ENUM(COMM_MCASP_CONF_XFMT) -ENUM(COMM_MCASP_CONF_ACLKXCTL) -ENUM(COMM_MCASP_CONF_AFSXCTL) -ENUM(COMM_MCASP_CONF_RFMT) -ENUM(COMM_MCASP_CONF_ACLKRCTL) -ENUM(COMM_MCASP_CONF_AFSRCTL) ENUM(COMM_MCASP_CONF_PDIR) } PruCommonFlags; #endif // __TIME__ diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index fd7648de6..ae1ed0fac 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -1341,9 +1341,10 @@ MCASP_SET_RX_NOT_CTAG_BEAST: LBBO r1, reg_comm_addr, COMM_MCASP_CONF_RFMT, 4 LBBO r2, reg_comm_addr, COMM_MCASP_CONF_AFSRCTL, 4 LBBO r3, reg_comm_addr, COMM_MCASP_CONF_ACLKRCTL, 4 - LBBO r4, reg_comm_addr, COMM_MCASP_CONF_RTDM, 4 - LBBO r5, reg_comm_addr, COMM_MCASP_CONF_RMASK, 4 - MCASP_SET_RX r1, r2, r3, MCASP_AHCLKRCTL_VALUE, r4, MCASP_RINTCTL_VALUE, r5 + LBBO r4, reg_comm_addr, COMM_MCASP_CONF_AHCLKRCTL, 4 + LBBO r5, reg_comm_addr, COMM_MCASP_CONF_RTDM, 4 + LBBO r6, reg_comm_addr, COMM_MCASP_CONF_RMASK, 4 + MCASP_SET_RX r1, r2, r3, r4, r5, MCASP_RINTCTL_VALUE, r6 QBA MCASP_SET_RX_DONE MCASP_SET_RX_NOT_BELA_TLV32_OR_BELA_MULTI_TLV: @@ -1367,9 +1368,10 @@ MCASP_SET_TX_NOT_CTAG_BEAST: LBBO r1, reg_comm_addr, COMM_MCASP_CONF_XFMT, 4 LBBO r2, reg_comm_addr, COMM_MCASP_CONF_AFSXCTL, 4 LBBO r3, reg_comm_addr, COMM_MCASP_CONF_ACLKXCTL, 4 - LBBO r4, reg_comm_addr, COMM_MCASP_CONF_XTDM, 4 - LBBO r5, reg_comm_addr, COMM_MCASP_CONF_XMASK, 4 - MCASP_SET_TX r1, r2, r3, MCASP_AHCLKXCTL_VALUE, r4, MCASP_XINTCTL_VALUE, r5 + LBBO r4, reg_comm_addr, COMM_MCASP_CONF_AHCLKXCTL, 4 + LBBO r5, reg_comm_addr, COMM_MCASP_CONF_XTDM, 4 + LBBO r6, reg_comm_addr, COMM_MCASP_CONF_XMASK, 4 + MCASP_SET_TX r1, r2, r3, r4, r5, MCASP_XINTCTL_VALUE, r6 QBA MCASP_SET_TX_DONE MCASP_SET_TX_NOT_BELA_TLV32_OR_BELA_MULTI_TLV: From 023e50bc948745ec59afa0a033169d6465b7b13c Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 10 Apr 2020 10:01:36 +0000 Subject: [PATCH 061/148] pru: we are supposed to poll GBLCTL, not [XR]BLCTL. Given how our SET_BIT writes are all read-set-write, there is no need to use [RX]GBLCTL in the first place --- pru/pru_rtaudio_irq.p | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index ae1ed0fac..311c2de1a 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -1398,8 +1398,8 @@ MCASP_SRCTL_NOT_BELA_TLV32_OR_BELA_MULTI_TLV: MCASP_REG_WRITE MCASP_XSTAT, 0xFF // Clear transmit errors MCASP_REG_WRITE MCASP_RSTAT, 0xFF // Clear receive errors - MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 1) // Set RHCLKRST - MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 9) // Set XHCLKRST + MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 1) // Set RHCLKRST + MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 9) // Set XHCLKRST // The above write sequence will have temporarily changed the AHCLKX frequency // The PLL needs time to settle or the sample rate will be unstable and possibly @@ -1411,12 +1411,12 @@ MCASP_INIT_WAIT: SUB r2, r2, 1 QBNE MCASP_INIT_WAIT, r2, 0 -MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 0) // Set RCLKRST -MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 8) // Set XCLKRST -MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 2) // Set RSRCLR -MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 10) // Set XSRCLR -MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 3) // Set RSMRST -MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 11) // Set XSMRST +MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 0) // Set RCLKRST +MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 8) // Set XCLKRST +MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 2) // Set RSRCLR +MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 10) // Set XSRCLR +MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 3) // Set RSMRST +MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 11) // Set XSMRST // Seems to be not required (was used to avoid transmit clock failure) //MCASP_REG_WRITE MCASP_XSTAT, 0xFF @@ -1477,8 +1477,8 @@ WRITE_FRAME_NOT_MULTI_TLV: #endif /* ENABLE_BELA_GENERIC_TDM */ WRITE_FRAME_DONE: -MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 4) // Set RFRST -MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 12) // Set XFRST +MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 4) // Set RFRST +MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 12) // Set XFRST // Initialisation LBBO reg_frame_mcasp_total, reg_comm_addr, COMM_BUFFER_MCASP_FRAMES, 4 // Total frame count for McASP From 695f03f9c446ec7755327cbc8cdce1d349502352 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 10 Apr 2020 10:13:06 +0000 Subject: [PATCH 062/148] pru: removed stale DBOX_CAPE define --- pru/pru_rtaudio_irq.p | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 311c2de1a..81bb174b1 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -20,7 +20,6 @@ // See https://github.com/BelaPlatform/Bela/issues/480 #define CTAG_IGNORE_UNUSED_INPUT_TDM_SLOTS -#define DBOX_CAPE // Define this to use new cape hardware #define CLOCK_BASE 0x44E00000 #define CLOCK_MCASP0 0x34 @@ -81,13 +80,8 @@ #define PRU_SYSTEM_EVENT_RTDM_WRITE_VALUE (1 << 5) | (PRU_SYSTEM_EVENT_RTDM - 16) #define C_ADC_DAC_MEM C24 // PRU0 mem -#ifdef DBOX_CAPE #define DAC_GPIO GPIO0 #define DAC_CS_PIN (1<<5) // GPIO0:5 = P9 pin 17 -#else -#define DAC_GPIO GPIO1 -#define DAC_CS_PIN (1<<16) // GPIO1:16 = P9 pin 15 -#endif #define DAC_TRM 0 // SPI transmit and receive #define DAC_WL 32 // Word length #define DAC_CLK_MODE 1 // SPI mode @@ -99,16 +93,11 @@ #define AD5668_DATA_OFFSET 4 #define AD5668_REF_OFFSET 0 -#ifdef DBOX_CAPE #define ADC_GPIO GPIO1 #define ADC_CS_PIN (1<<16) // GPIO1:16 = P9 pin 15 // for BELA_MINI, this is the same as DAC_CS_PIN, but the latter is disabled in DAC_WRITE #define ADC_GPIO_BELA_MINI GPIO0 -#define ADC_CS_PIN_BELA_MINI (1<<5) // GPIO1:5 = P1 pin 6 -#else /* DBOX_CAPE */ -#define ADC_GPIO GPIO1 -#define ADC_CS_PIN (1<<17) // GPIO1:17 = P9 pin 23 -#endif /* DBOX_CAPE */ +#define ADC_CS_PIN_BELA_MINI (1<<5) // GPIO0:5 = P1 pin 6 #define ADC_TRM 0 // SPI transmit and receive #define ADC_WL 16 // Word length #define ADC_CLK_MODE 0 // SPI mode @@ -270,22 +259,10 @@ // Constants used for this particular audio setup #define MCASP_BASE MCASP0_BASE #define MCASP_DATAPORT MCASP0_DATAPORT -#ifdef DBOX_CAPE #define MCASP_SRCTL_X MCASP_SRCTL2 // Ser. 2 is transmitter #define MCASP_SRCTL_R MCASP_SRCTL0 // Ser. 0 is receiver #define MCASP_XBUF MCASP_XBUF2 #define MCASP_RBUF MCASP_RBUF0 -#else -#define MCASP_SRCTL_X MCASP_SRCTL3 // Ser. 3 is transmitter -#define MCASP_SRCTL_R MCASP_SRCTL2 // Ser. 2 is receiver -#define MCASP_XBUF MCASP_XBUF3 -#define MCASP_RBUF MCASP_RBUF2 -#endif - -#ifdef DBOX_CAPE -#else // DBOX_CAPE -#define MCASP_OUTPUT_PINS (1 << 3) // Which pins are outputs -#endif // DBOX_CAPE #define MCASP_DATA_MASK 0xFFFF // 16 bit data #define MCASP_AHCLKRCTL_VALUE 0x8001 // Internal clock, not inv, /2; irrelevant? @@ -1304,11 +1281,7 @@ SPI_INIT_DONE: MCASP_REG_WRITE MCASP_PWRIDLESYSCONFIG, 0x02 // Power on MCASP_REG_WRITE MCASP_PFUNC, 0x00 // All pins are McASP // Set pin direction -#ifdef DBOX_CAPE LBBO r2, reg_comm_addr, COMM_MCASP_CONF_PDIR, 4 -#else // DBOX_CAPE - MOV r2, MCASP_OUTPUT_PINS -#endif // DBOX_CAPE MCASP_REG_WRITE MCASP_PDIR, r2 MCASP_REG_WRITE MCASP_DLBCTL, 0x00 // disable loopback MCASP_REG_WRITE MCASP_DITCTL, 0x00A // disable DIT From da2c8bded05f9ff71308fb025d885ef4832b9dc3 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 10 Apr 2020 16:12:10 +0000 Subject: [PATCH 063/148] core: I2c_MultiTLVAudio mclk initialization --- core/I2c_MultiTLVCodec.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 1faa7bdd4..4724420d7 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -63,6 +63,7 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(int i2cBus, int i2cAddress, bool isVerbose params.startingSlot = slotNum; params.generatesBclk = true; params.generatesWclk = codecWclkMaster; + params.mclk = masterCodec->getMcaspConfig().getValidAhclk(24000000); masterCodec->setParameters(params); } params.generatesBclk = false; From 18735e785d463732d6660d680603f8c32d13aecd Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 10 Apr 2020 16:43:11 +0000 Subject: [PATCH 064/148] pru: moved bits of code around following the instructions in the TRM to the letter and (suprise) it works! i.e.: no longer TX underrun as soon as we start. Also, there seems not to be any need for codec restarting when a PRU error is encountered. --- pru/pru_rtaudio_irq.p | 203 +++++++++++++++++++++++++++++------------- 1 file changed, 143 insertions(+), 60 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 81bb174b1..9993cd60c 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -1258,6 +1258,37 @@ SPI_WAIT_RESET: ADC_WRITE r2, r2 SPI_INIT_DONE: + + // Check how many channels we have + READ_ACTIVE_CHANNELS_INTO_FLAGS + GET_NUM_AUDIO_IN_CHANNELS r2 + GET_NUM_AUDIO_OUT_CHANNELS r3 + // And that they are a valid number (at least one input OR output channel) + QBNE CHANNEL_COUNT_NOT_ZERO, r2, 0 + QBNE CHANNEL_COUNT_NOT_ZERO, r3, 0 + SEND_ERROR_TO_ARM ARM_ERROR_INVALID_INIT + HALT +CHANNEL_COUNT_NOT_ZERO: + +// Initialisation of PRU memory pointers and counters + LBBO reg_frame_mcasp_total, reg_comm_addr, COMM_BUFFER_MCASP_FRAMES, 4 // Total frame count for McASP + LBBO reg_frame_spi_total, reg_comm_addr, COMM_BUFFER_SPI_FRAMES, 4 // Total frame count for SPI + MOV reg_dac_buf0, 0 // DAC buffer 0 start pointer + LSL reg_dac_buf1, reg_frame_spi_total, 1 // DAC buffer 1 start pointer = N[ch]*2[bytes]*bufsize + ADD reg_dac_buf1, reg_dac_buf1, reg_dac_buf0 + LMBD r2, reg_num_channels, 1 // Returns 1, 2 or 3 depending on the number of channels + LSL reg_dac_buf1, reg_dac_buf1, r2 // Multiply by 2, 4 or 8 to get the N[ch] scaling above + MOV reg_mcasp_buf0, REG_MCASP_BUF0_INIT // McASP DAC buffer 0 start pointer + COMPUTE_SIZE_OF_MCASP_DAC_BUFFER r2 + ADD reg_mcasp_buf1, r2, reg_mcasp_buf0 + CLR reg_flags, reg_flags, FLAG_BIT_BUFFER1 // Bit 0 holds which buffer we are on + SET reg_flags, reg_flags, FLAG_BIT_MCASP_TX_FIRST_FRAME // 0 = first half of frame period + SET reg_flags, reg_flags, FLAG_BIT_MCASP_RX_FIRST_FRAME + CLR reg_flags, reg_flags, FLAG_BIT_MCASP_TX_PROCESSED // Jump not NEXT_FRAME label if both ADCs and DACs have been processed + CLR reg_flags, reg_flags, FLAG_BIT_MCASP_RX_PROCESSED + SET reg_flags, reg_flags, FLAG_BIT_MCSPI_FIRST_FOUR_CH + MOV r2, 0 + SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4 // Start with frame count of 0 // enable MCASP interface clock in PRCM MOV r2, 0x30002 @@ -1265,6 +1296,15 @@ SPI_INIT_DONE: SBBO r2, r3, 0, 4 // Prepare McASP0 for audio +MCASP_INIT: +MCASP_ERROR_RECOVERY: // we also come back here if there are any issues while running + +// Comments on McASP initialisation below are from the AM335x TRM, TI SPRUH73H +// 22.3.12.2 Transmit/Receive Section Initialization +// You must follow the following steps to properly configure the McASP. If +// external clocks are used, they should be present prior to the following +// initialization steps +// 1. Reset McASP to default values by setting GBLCTL = 0. MCASP_REG_WRITE MCASP_GBLCTL, 0 // Disable McASP // Configure FIFOs LBBO r2, reg_comm_addr, COMM_MCASP_CONF_WFIFOCTL, 4 @@ -1278,26 +1318,13 @@ SPI_INIT_DONE: MCASP_REG_WRITE_EXT MCASP_SRCTL4, 0 MCASP_REG_WRITE_EXT MCASP_SRCTL5, 0 +// 2. Configure all McASP registers except GBLCTL in the following order: +// (a) Power Idle SYSCONFIG: PWRIDLESYSCONFIG. MCASP_REG_WRITE MCASP_PWRIDLESYSCONFIG, 0x02 // Power on - MCASP_REG_WRITE MCASP_PFUNC, 0x00 // All pins are McASP - // Set pin direction - LBBO r2, reg_comm_addr, COMM_MCASP_CONF_PDIR, 4 - MCASP_REG_WRITE MCASP_PDIR, r2 - MCASP_REG_WRITE MCASP_DLBCTL, 0x00 // disable loopback - MCASP_REG_WRITE MCASP_DITCTL, 0x00A // disable DIT - - // Check how many channels we have - READ_ACTIVE_CHANNELS_INTO_FLAGS - GET_NUM_AUDIO_IN_CHANNELS r2 - GET_NUM_AUDIO_OUT_CHANNELS r3 - // And that they are a valid number - QBNE CHANNEL_COUNT_NOT_ZERO, r2, 0 - QBNE CHANNEL_COUNT_NOT_ZERO, r3, 0 - SEND_ERROR_TO_ARM ARM_ERROR_INVALID_INIT - HALT -CHANNEL_COUNT_NOT_ZERO: -// set MCASP RX +// (b) Receive registers: RMASK, RFMT, AFSRCTL, ACLKRCTL, AHCLKRCTL, RTDM, +// RINTCTL, RCLKCHK. If external clocks AHCLKR and/or ACLKR are used, they must +// be running already for proper synchronization of the GBLCTL register. #ifdef ENABLE_CTAG_FACE IF_NOT_CTAG_FACE_JMP_TO MCASP_SET_RX_NOT_CTAG_FACE MCASP_SET_RX CTAG_FACE_MCASP_DATA_FORMAT_RX_VALUE, CTAG_FACE_MCASP_AFSRCTL_VALUE, CTAG_FACE_MCASP_ACLKRCTL_VALUE, CTAG_FACE_MCASP_AHCLKRCTL_VALUE, CTAG_FACE_MCASP_RTDM_VALUE, CTAG_FACE_MCASP_RINTCTL_VALUE, MCASP_DATA_MASK @@ -1317,12 +1344,16 @@ MCASP_SET_RX_NOT_CTAG_BEAST: LBBO r4, reg_comm_addr, COMM_MCASP_CONF_AHCLKRCTL, 4 LBBO r5, reg_comm_addr, COMM_MCASP_CONF_RTDM, 4 LBBO r6, reg_comm_addr, COMM_MCASP_CONF_RMASK, 4 +//TODO: set RCLKCHK MCASP_SET_RX r1, r2, r3, r4, r5, MCASP_RINTCTL_VALUE, r6 QBA MCASP_SET_RX_DONE MCASP_SET_RX_NOT_BELA_TLV32_OR_BELA_MULTI_TLV: MCASP_SET_RX_DONE: +// (c) Transmit registers: XMASK, XFMT, AFSXCTL, ACLKXCTL, AHCLKXCTL, XTDM, +// XINTCTL, XCLKCHK. If external clocks AHCLKX and/or ACLKX are used, they must be +// running already for proper synchronization of the GBLCTL register. // set MCASP TX #ifdef ENABLE_CTAG_FACE IF_NOT_CTAG_FACE_JMP_TO MCASP_SET_TX_NOT_CTAG_FACE @@ -1344,12 +1375,14 @@ MCASP_SET_TX_NOT_CTAG_BEAST: LBBO r4, reg_comm_addr, COMM_MCASP_CONF_AHCLKXCTL, 4 LBBO r5, reg_comm_addr, COMM_MCASP_CONF_XTDM, 4 LBBO r6, reg_comm_addr, COMM_MCASP_CONF_XMASK, 4 +//TODO: set XCLKCHK MCASP_SET_TX r1, r2, r3, r4, r5, MCASP_XINTCTL_VALUE, r6 QBA MCASP_SET_TX_DONE MCASP_SET_TX_NOT_BELA_TLV32_OR_BELA_MULTI_TLV: MCASP_SET_TX_DONE: +// (d) Serializer registers: SRCTL[n]. IF_NOT_CTAG_JMP_TO MCASP_SRCTL_NOT_CTAG MCASP_REG_WRITE_EXT MCASP_SRCTL_R, 0x02 // Set up receive serialiser MCASP_REG_WRITE_EXT MCASP_SRCTL_X, 0x01 // Set up transmit serialiser @@ -1368,15 +1401,39 @@ MCASP_SRCTL_NOT_CTAG: MCASP_REG_WRITE_EXT MCASP_SRCTL3, r2 MCASP_SRCTL_NOT_BELA_TLV32_OR_BELA_MULTI_TLV: - MCASP_REG_WRITE MCASP_XSTAT, 0xFF // Clear transmit errors - MCASP_REG_WRITE MCASP_RSTAT, 0xFF // Clear receive errors +// (e) Global registers: Registers PFUNC, PDIR, DITCTL, DLBCTL, AMUTE. Note that +// PDIR should only be programmed after the clocks and frames are set up in the +// steps above. This is because the moment a clock pin is configured as an output +// in PDIR, the clock pin starts toggling at the rate defined in the corresponding +// clock control register. Therefore you must ensure that the clock control +// register is configured appropriately before you set the pin to be an output. A +// similar argument applies to the frame sync pins. Also note that the reset state +// for the transmit high-frequency clock divide register (HCLKXDIV) is +// divide-by-1, and the divide-by-1 clocks are not gated by the transmit +// high-frequency clock divider reset enable (XHCLKRST). + + MCASP_REG_WRITE MCASP_PFUNC, 0x00 // All pins are McASP + // Set pin direction + LBBO r2, reg_comm_addr, COMM_MCASP_CONF_PDIR, 4 + MCASP_REG_WRITE MCASP_PDIR, r2 + MCASP_REG_WRITE MCASP_DITCTL, 0x00A // disable DIT + MCASP_REG_WRITE MCASP_DLBCTL, 0x00 // disable loopback + MCASP_REG_WRITE MCASP_AMUTE, 0x0 // disable audio mute + +// (f) DIT registers: For DIT mode operation, set up registers DITCSRA[n], +// DITCSRB[n], DITUDRA[n], and DITUDRB[n]. [not needed here] +// 3. Start the respective high-frequency serial clocks AHCLKX and/or AHCLKR. This +// step is necessary even if external high-frequency serial clocks are used: +// (a) Take the respective internal high-frequency serial clock divider(s) out of +// reset by setting the RHCLKRST bit for the receiver and/or the XHCLKRST bit for +// the transmitter in GBLCTL. All other bits in GBLCTL should be held at 0. MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 1) // Set RHCLKRST MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 9) // Set XHCLKRST -// The above write sequence will have temporarily changed the AHCLKX frequency -// The PLL needs time to settle or the sample rate will be unstable and possibly -// cause an underrun. Give it ~1ms before going on. +// The above write sequence may have temporarily changed the AHCLKX frequency +// The codec's PLL (if any) needs time to settle or the sample rate will be +// unstable and possibly cause an underrun. Give it ~1ms before going on. // 10ns per loop iteration = 10^-8s --> 10^5 iterations needed MOV r2, 100000 @@ -1386,14 +1443,44 @@ MCASP_INIT_WAIT: MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 0) // Set RCLKRST MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 8) // Set XCLKRST + +// 5. Setup data acquisition as required: +// (a) If DMA is used to service the McASP, set up data acquisition as desired +// and start the DMA in this step, before the McASP is taken out of reset. +// (b) If CPU interrupt is used to service the McASP, enable the transmit and/ +// or receive interrupt as required. +// (c) If CPU polling is used to service the McASP, no action is required in +// this step. + +// [not mcuh to do here, McASP->PRU interrupts have been set up by the rtdm driver] + +// 6. Activate serializers. +// (a) Before starting, clear the respective transmitter and receiver status registers by writing XSTAT = FFFFh and RSTAT = FFFFh. +MCASP_REG_WRITE MCASP_XSTAT, 0xFFFF +MCASP_REG_WRITE MCASP_RSTAT, 0xFFFF +// (b) Take the respective serializers out of reset by setting the RSRCLR bit +// for the receiver and/or the XSRCLR bit for the transmitter in GBLCTL. MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 2) // Set RSRCLR MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 10) // Set XSRCLR -MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 3) // Set RSMRST -MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 11) // Set XSMRST -// Seems to be not required (was used to avoid transmit clock failure) -//MCASP_REG_WRITE MCASP_XSTAT, 0xFF -//MCASP_REG_WRITE MCASP_RSTAT, 0xFF +// 7. Verify that all transmit buffers are serviced. Skip this step if the +// transmitter is not used. Also, skip this step if time slot 0 is selected as +// inactive (special cases, see Figure 22-21, second waveform). As soon as the +// transmit serializer is taken out of reset, XDATA in the XSTAT register is set, +// indicating that XBUF is empty and ready to be serviced. The XDATA status causes +// an DMA event AXEVT to be generated, and can cause an interrupt AXINT to be +// generated if it is enabled in the XINTCTL register. +// (a) If DMA is used to service the McASP, the DMA automatically services the +// McASP upon receiving AXEVT. Before proceeding in this step, you should verify +// that the XDATA bit in the XSTAT is cleared to 0, indicating that all transmit +// buffers are already serviced by the DMA. +// (b) If CPU interrupt is used to service the McASP, interrupt service routine is +// entered upon the AXINT interrupt. The interrupt service routine should service +// the XBUF registers. Before proceeding in this step, you should verify that the +// XDATA bit in XSTAT is cleared to 0, indicating that all transmit buffers are +// already serviced by the CPU. +// (c) If CPU polling is used to service the McASP, the XBUF registers should be +// written to in this step. // Write a full frame to transmit FIFOs to prevent underflow and keep slots synced // Can be probably ignored if first underrun gets ignored for better performance => TODO: test @@ -1450,28 +1537,13 @@ WRITE_FRAME_NOT_MULTI_TLV: #endif /* ENABLE_BELA_GENERIC_TDM */ WRITE_FRAME_DONE: -MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 4) // Set RFRST -MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 12) // Set XFRST +// 8. Release state machines from reset. +// (a) Take the respective state machine(s) out of reset by setting the RSMRST bit +// for the receiver and/or the XSMRST bit for the transmitter in GBLCTL. All other +// bits in GBLCTL should be left at the previous state. -// Initialisation - LBBO reg_frame_mcasp_total, reg_comm_addr, COMM_BUFFER_MCASP_FRAMES, 4 // Total frame count for McASP - LBBO reg_frame_spi_total, reg_comm_addr, COMM_BUFFER_SPI_FRAMES, 4 // Total frame count for SPI - MOV reg_dac_buf0, 0 // DAC buffer 0 start pointer - LSL reg_dac_buf1, reg_frame_spi_total, 1 // DAC buffer 1 start pointer = N[ch]*2[bytes]*bufsize - ADD reg_dac_buf1, reg_dac_buf1, reg_dac_buf0 - LMBD r2, reg_num_channels, 1 // Returns 1, 2 or 3 depending on the number of channels - LSL reg_dac_buf1, reg_dac_buf1, r2 // Multiply by 2, 4 or 8 to get the N[ch] scaling above - MOV reg_mcasp_buf0, REG_MCASP_BUF0_INIT // McASP DAC buffer 0 start pointer - COMPUTE_SIZE_OF_MCASP_DAC_BUFFER r2 - ADD reg_mcasp_buf1, r2, reg_mcasp_buf0 - CLR reg_flags, reg_flags, FLAG_BIT_BUFFER1 // Bit 0 holds which buffer we are on - SET reg_flags, reg_flags, FLAG_BIT_MCASP_TX_FIRST_FRAME // 0 = first half of frame period - SET reg_flags, reg_flags, FLAG_BIT_MCASP_RX_FIRST_FRAME - CLR reg_flags, reg_flags, FLAG_BIT_MCASP_TX_PROCESSED // Jump not NEXT_FRAME label if both ADCs and DACs have been processed - CLR reg_flags, reg_flags, FLAG_BIT_MCASP_RX_PROCESSED - SET reg_flags, reg_flags, FLAG_BIT_MCSPI_FIRST_FOUR_CH - MOV r2, 0 - SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4 // Start with frame count of 0 +MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 3) // Set RSMRST +MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 11) // Set XSMRST #ifdef ATTEMPT_TO_RESYNC_BELA_ADC // for BELA_TLV32, the left and right channels are swapped, so that each frame contains: @@ -1511,6 +1583,21 @@ DONELOOPTHIS: MCASP_REG_WRITE MCASP_RFMT, r3 // Restore original value #endif // ATTEMPT_TO_RESYNC_BELA_ADC +// 9. Release frame sync generators from reset. Note that it is necessary to +// release the internal frame sync generators from reset, even if an external +// frame sync is being used, because the frame sync error detection logic is built +// into the frame sync generator. +// (a) Take the respective frame sync generator(s) out of reset by setting the +// RFRST bit for the receiver, and/or the XFRST bit for the transmitter in GBLCTL. +// All other bits in GBLCTL should be left at the previous state. +MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 4) // Set RFRST +MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 12) // Set XFRST +// 10. Upon the first frame sync signal, McASP transfers begin. The McASP +// synchronizes to an edge on the frame sync pin, not the level on the frame sync +// pin. + +// [In other words: we are good to go] + WRITE_ONE_BUFFER: // Write a single buffer of DAC samples and read a buffer of ADC samples @@ -1571,18 +1658,16 @@ NOT_NEXT_FRAME: // Check if ARM says should finish: flag is zero as long as it should run LBBO r27, reg_comm_addr, COMM_SHOULD_STOP, 4 - QBNE GO_TO_CLEANUP, r27, 0 + QBEQ CONTINUE_RUNNING, r27, 0 + JAL r28.w0, CLEANUP // JAL allows longer jumps than JMP, but we actually ignore r28 (will never come back) +CONTINUE_RUNNING: SUB r28, r28, 1 QBNE MCASP_CHECK_TX_ERROR_END, r28, 0 // If we go through EVENT_LOOP_TIMEOUT_COUNT iterations without receiving // an interrupt, an error must have occurred SEND_ERROR_TO_ARM ARM_ERROR_TIMEOUT - JMP START // TODO: should HALT and wait for ARM to restart - -GO_TO_CLEANUP: - JMP CLEANUP - + JMP MCASP_ERROR_RECOVERY MCASP_CHECK_TX_ERROR_END: QBBC INNER_EVENT_LOOP, r31, PRU_INTR_BIT_CH1 @@ -1618,12 +1703,12 @@ MCASP_TX_INTR_RECEIVED: // mcasp_x_intr_pend MCASP_TX_UNDERRUN_OCCURRED: SEND_ERROR_TO_ARM ARM_ERROR_XUNDRUN MCASP_REG_WRITE_EXT MCASP_XSTAT, 1 << MCASP_XSTAT_XUNDRN_BIT // Clear underrun bit (0) - JMP START // TODO: should HALT and wait for ARM to restart + JMP MCASP_ERROR_RECOVERY MCASP_TX_UNEXPECTED_FRAME_SYNC_OCCURRED: SEND_ERROR_TO_ARM ARM_ERROR_XSYNCERR MCASP_REG_WRITE_EXT MCASP_XSTAT, 1 << MCASP_XSTAT_XSYNCERR_BIT // Clear frame sync error bit (1) - JMP START // TODO: should HALT and wait for ARM to restart + JMP MCASP_ERROR_RECOVERY MCASP_TX_CLOCK_FAILURE_OCCURRED: // A McASP transmit clock error is automatically solved by resetting the bit and jumping back @@ -1636,7 +1721,7 @@ MCASP_TX_CLOCK_FAILURE_OCCURRED: MCASP_TX_DMA_ERROR_OCCURRED: SEND_ERROR_TO_ARM ARM_ERROR_XDMAERR MCASP_REG_WRITE_EXT MCASP_XSTAT, 1 << MCASP_XSTAT_XDMAERR_BIT // Clear DMA error bit (7) - JMP START // TODO: should HALT and wait for ARM to restart + JMP MCASP_ERROR_RECOVERY MCASP_TX_ERROR_HANDLE_END: @@ -1703,8 +1788,6 @@ LOAD_AUDIO_FRAME_MULTI_TLV_LT16CHAN: QBA LOAD_AUDIO_FRAME_DONE LOAD_AUDIO_FRAME_NOT_MULTI_TLV: #endif /* ENABLE_BELA_GENERIC_TDM */ - SEND_ERROR_TO_ARM ARM_ERROR_INVALID_INIT - HALT LOAD_AUDIO_FRAME_DONE: //TODO: Change data structure in RAM to 32 bit samples From 1a767234df59bdfdce8b4efedb99133c9db49197 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 10 Apr 2020 17:14:20 +0000 Subject: [PATCH 065/148] core: PRU given how resetting the codec is no longer needed to fix McASP errors (not that it ever actually was, but for some black magic reason it was), we removed the need for a pointer to gAudioCodec --- core/PRU.cpp | 12 ++---------- core/RTAudio.cpp | 2 +- include/PRU.h | 3 +-- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/core/PRU.cpp b/core/PRU.cpp index c066cf830..a382cf422 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -211,7 +211,7 @@ extern "C" { #endif /* USE_NEON_FORMAT_CONVERSION */ // Constructor: specify a PRU number (0 or 1) -PRU::PRU(InternalBelaContext *input_context, AudioCodec *audio_codec) +PRU::PRU(InternalBelaContext *input_context) : context(input_context), pru_number(1), initialised(false), @@ -220,8 +220,7 @@ PRU::PRU(InternalBelaContext *input_context, AudioCodec *audio_codec) digital_enabled(false), gpio_enabled(false), led_enabled(false), pru_buffer_comm(0), audio_expander_input_history(0), audio_expander_output_history(0), - audio_expander_filter_coeff(0), pruUsesMcaspIrq(false), belaHw(BelaHw_NoHw), - codec(audio_codec) + audio_expander_filter_coeff(0), pruUsesMcaspIrq(false), belaHw(BelaHw_NoHw) { } @@ -839,14 +838,7 @@ int PRU::testPruError() verbose && rt_fprintf(stderr, "Unknown PRU error: %d\n", errorCode); ret = 1; } - codec->stopAudio(); - codec->reset(); - //codec->initCodec(); - if(codec->startAudio(0)) { - rt_fprintf(stderr, "Error restarting codec\n"); - } pru_buffer_comm[PRU_COMM_ERROR_OCCURRED] = 0; - // TODO: should restart PRU and codec from scratch return ret; } else { return 0; diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index e2d0bf83e..02afe9a63 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -558,7 +558,7 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) gContext.flags |= BELA_FLAG_DETECT_UNDERRUNS; // Use PRU for audio - gPRU = new PRU(&gContext, gAudioCodec); + gPRU = new PRU(&gContext); // Get the PRU memory buffers ready to go if(gPRU->initialise(belaHw, settings->pruNumber, settings->uniformSampleRate, diff --git a/include/PRU.h b/include/PRU.h index 30a7f74d5..ae12bbd77 100644 --- a/include/PRU.h +++ b/include/PRU.h @@ -147,7 +147,7 @@ class PRU public: // Constructor - PRU(InternalBelaContext *input_context, AudioCodec *audio_codec); + PRU(InternalBelaContext *input_context); // Destructor ~PRU(); @@ -208,5 +208,4 @@ class PRU Gpio stopButton; // Monitoring the bela cape button Gpio underrunLed; // Flashing an LED upon underrun - AudioCodec *codec; // Required to hard reset audio codec from loop }; From 85b29a1f16004df90a9c0ab99c315323d08ede50 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 13 Apr 2020 10:00:24 +0000 Subject: [PATCH 066/148] make: added MultiTdmCodec to libbela --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 83fe2513e..2ac97098d 100644 --- a/Makefile +++ b/Makefile @@ -393,7 +393,8 @@ ALL_DEPS += $(addprefix build/core/,$(notdir $(CORE_C_SRCS:.c=.d))) CORE_CPP_SRCS = $(filter-out core/default_main.cpp core/default_libpd_render.cpp, $(wildcard core/*.cpp)) CORE_OBJS := $(CORE_OBJS) $(addprefix build/core/,$(notdir $(CORE_CPP_SRCS:.cpp=.o))) -CORE_CORE_OBJS := build/core/RTAudio.o build/core/PRU.o build/core/RTAudioCommandLine.o build/core/I2c_Codec.o build/core/I2c_MultiTLVCodec.o build/core/Spi_Codec.o build/core/math_runfast.o build/core/GPIOcontrol.o build/core/PruBinary.o build/core/board_detect.o build/core/DataFifo.o build/core/BelaContextFifo.o build/core/BelaContextSplitter.o build/core/MiscUtilities.o build/core/Mmap.o build/core/Mcasp.o +CORE_CORE_OBJS := build/core/RTAudio.o build/core/PRU.o build/core/RTAudioCommandLine.o build/core/I2c_Codec.o build/core/I2c_MultiTLVCodec.o build/core/I2c_MultiTdmCodec.o build/core/Spi_Codec.o build/core/math_runfast.o build/core/GPIOcontrol.o build/core/PruBinary.o build/core/board_detect.o build/core/DataFifo.o build/core/BelaContextFifo.o build/core/BelaContextSplitter.o build/core/MiscUtilities.o build/core/Mmap.o build/core/Mcasp.o +EXTRA_CORE_OBJS := $(filter-out $(CORE_CORE_OBJS), $(CORE_OBJS)) ALL_DEPS += $(addprefix build/core/,$(notdir $(CORE_CPP_SRCS:.cpp=.d))) CORE_ASM_SRCS := $(wildcard core/*.S) From 3864ff51da7de109b32c206640b3e5eace48af9a Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 17 Apr 2020 11:17:34 +0000 Subject: [PATCH 067/148] core: MultiTdmCodec: a more realistic use case --- core/I2c_MultiTdmCodec.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/I2c_MultiTdmCodec.cpp b/core/I2c_MultiTdmCodec.cpp index 4d94aeceb..76e270747 100644 --- a/core/I2c_MultiTdmCodec.cpp +++ b/core/I2c_MultiTdmCodec.cpp @@ -18,16 +18,16 @@ McaspConfig& I2c_MultiTdmCodec::getMcaspConfig() mcaspConfig.params.dataSize = 16; mcaspConfig.params.inChannels = getNumIns(); mcaspConfig.params.outChannels = getNumOuts(); - mcaspConfig.params.outSerializers = {1, 2}; + mcaspConfig.params.inSerializers = {0, 1}; return mcaspConfig; } unsigned int I2c_MultiTdmCodec::getNumIns() { - return 2; + return 8; } unsigned int I2c_MultiTdmCodec::getNumOuts() { - return 4; + return 8; } From 83a725ed8535bb877fe6efe351fc516ccb74fc69 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 11 May 2020 14:51:25 +0000 Subject: [PATCH 068/148] I2c_Codec: actually using the verbose parameter in the constructor --- core/I2c_Codec.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 21ba2a9ba..03cce56d5 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -21,6 +21,7 @@ I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, CodecType type, bool isVerbose /*= false*/) : codecType(type), dacVolumeHalfDbs(0), adcVolumeHalfDbs(0), hpVolumeHalfDbs(0) , running(false) + , verbose(isVerbose) , mode(InitMode_init) { params.slotSize = 16; From 28642060216f7c7c43d9f5b2fd412a21aeaafbfe Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 11 May 2020 15:04:25 +0000 Subject: [PATCH 069/148] Mcasp.cpp: compatible with g++-6.3 --- core/Mcasp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/Mcasp.cpp b/core/Mcasp.cpp index 1ce4f8a7a..52a92055e 100644 --- a/core/Mcasp.cpp +++ b/core/Mcasp.cpp @@ -4,9 +4,10 @@ #include #include -McaspConfig::McaspConfig() : - params({.auxClkIn = 24000000}) +McaspConfig::McaspConfig() { + params = {0}; + params.auxClkIn = 24000000; } double McaspConfig::getValidAhclk(double desiredClk, unsigned int* outDiv) From 46b7787fb51a47c5a394cd7ea46b02eb3840a9ed Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Wed, 17 Jun 2020 15:51:53 +0000 Subject: [PATCH 070/148] I2c_MultiTLVCodec: passing multiple I2C busses and customised TdmConfig settings. Exiting early if no codec found. --- core/I2c_MultiTLVCodec.cpp | 70 +++++++++++++++++++------------------ core/RTAudio.cpp | 2 +- include/I2c_MultiTLVCodec.h | 9 ++++- 3 files changed, 45 insertions(+), 36 deletions(-) diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 4724420d7..4c13af8c9 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -6,47 +6,50 @@ * I2C addresses). Codec 0 provides the clock signals * via its PLL and the other codecs are clocked to it. * - * Created on: August 9, 2019 - * Author: Andrew McPherson */ #include #include "../include/I2c_MultiTLVCodec.h" +static const unsigned int kDataSize = 16; #undef CODEC_WCLK_MASTER // Match this with pru_rtaudio_irq.p -I2c_MultiTLVCodec::I2c_MultiTLVCodec(int i2cBus, int i2cAddress, bool isVerbose /*= false*/) +I2c_MultiTLVCodec::I2c_MultiTLVCodec(std::vector i2cBusses, int i2cAddress, TdmConfig tdmConfig, bool isVerbose /*= false*/) : masterCodec(0), running(false), verbose(isVerbose) { - // for(int address = i2cAddress + 3; address >= i2cAddress; address--) { - for(int address = i2cAddress; address < i2cAddress + 4; address++) { - // Check for presence of TLV codec and take the first one we find as the master codec - // TODO: this code assumes the first codec is a 3104 (Bela Mini cape), which might not always be true - I2c_Codec::CodecType type = (address == i2cAddress) ? I2c_Codec::TLV320AIC3104 : I2c_Codec::TLV320AIC3106; - I2c_Codec *testCodec = new I2c_Codec(i2cBus, address, type); - if(testCodec->initCodec() != 0) { - delete testCodec; - if(verbose) { - fprintf(stderr, "Error initialising I2C codec on bus %d address %d\n", i2cBus, address); + for(auto i2cBus : i2cBusses) { + for(int address = i2cAddress; address < i2cAddress + 4; address++) { + // Check for presence of TLV codec and take the first one we find as the master codec + // TODO: this code assumes the first codec is a 3104 (Bela Mini cape), which might not always be true + I2c_Codec::CodecType type = (address == i2cAddress) ? I2c_Codec::TLV320AIC3104 : I2c_Codec::TLV320AIC3106; + I2c_Codec *testCodec = new I2c_Codec(i2cBus, address, type); + if(testCodec->initCodec() != 0) { + delete testCodec; + if(verbose) { + fprintf(stderr, "Error initialising I2C codec on bus %d address %d\n", i2cBus, address); + } } - } - else { - // codec found - if(verbose) { - fprintf(stderr, "Found I2C codec on bus %d address %d\n", i2cBus, address); + else { + // codec found + if(verbose) { + fprintf(stderr, "Found I2C codec on bus %d address %d\n", i2cBus, address); + } + + if(!masterCodec) + masterCodec = testCodec; + else + extraCodecs.push_back(testCodec); } - - if(!masterCodec) - masterCodec = testCodec; - else - extraCodecs.push_back(testCodec); } } + if(!masterCodec) { + return; + } // Master codec generates bclk (and possibly wclk) with its PLL - // and occupies the first two slots - const int slotSize = 16; - const unsigned int bitDelay = 0; - unsigned int slotNum = 0; + // and occupies the first two slots starting from tdmConfig.firstSlot + const unsigned int slotSize = tdmConfig.slotSize; + const unsigned int bitDelay = tdmConfig.bitDelay; + unsigned int slotNum = tdmConfig.firstSlot; bool codecWclkMaster = #ifdef CODEC_WCLK_MASTER true; // Main codec generates word clock @@ -59,13 +62,11 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(int i2cBus, int i2cAddress, bool isVerbose params.bitDelay = bitDelay; params.dualRate = false; params.tdmMode = true; - if(masterCodec) { - params.startingSlot = slotNum; - params.generatesBclk = true; - params.generatesWclk = codecWclkMaster; - params.mclk = masterCodec->getMcaspConfig().getValidAhclk(24000000); - masterCodec->setParameters(params); - } + params.startingSlot = slotNum; + params.generatesBclk = true; + params.generatesWclk = codecWclkMaster; + params.mclk = masterCodec->getMcaspConfig().getValidAhclk(24000000); + masterCodec->setParameters(params); params.generatesBclk = false; params.generatesWclk = false; for(auto& codec : extraCodecs) { @@ -278,6 +279,7 @@ I2c_MultiTLVCodec::~I2c_MultiTLVCodec() McaspConfig& I2c_MultiTLVCodec::getMcaspConfig() { mc = masterCodec->getMcaspConfig(); + mc.params.dataSize = kDataSize; mc.params.inChannels = getNumIns(); mc.params.outChannels = getNumOuts(); return mc; diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 02afe9a63..ef1917561 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -419,7 +419,7 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) gDisabledCodec = new I2c_Codec(codecI2cBus, codecI2cAddress, I2c_Codec::TLV320AIC3104, gRTAudioVerbose); } else if(belaHw == BelaHw_BelaMiniMultiAudio) - gAudioCodec = new I2c_MultiTLVCodec(codecI2cBus, codecI2cAddress, gRTAudioVerbose); + gAudioCodec = new I2c_MultiTLVCodec({codecI2cBus}, codecI2cAddress, {}, gRTAudioVerbose); else if(belaHw == BelaHw_BelaMiniMultiTdm) gAudioCodec = new I2c_MultiTdmCodec(codecI2cBus, codecI2cAddress, gRTAudioVerbose); else if(Bela_hwContains(belaHw, Tlv320aic3104)) diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index 13ec16350..d150037d9 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -18,6 +18,13 @@ class I2c_MultiTLVCodec : public AudioCodec { public: + class TdmConfig { + public: + TdmConfig(){}; + unsigned int slotSize = 16; + unsigned int bitDelay = 0; + unsigned int firstSlot = 0; + }; int initCodec(); int startAudio(int dual_rate); int stopAudio(); @@ -38,7 +45,7 @@ class I2c_MultiTLVCodec : public AudioCodec int debugReadRegister(int codecNum, int regNum); McaspConfig& getMcaspConfig(); - I2c_MultiTLVCodec(int i2cBus, int i2cAddress, bool verbose = false); + I2c_MultiTLVCodec(std::vector i2cBusses, int i2cAddress, TdmConfig tdmConfig = TdmConfig(), bool verbose = false); ~I2c_MultiTLVCodec(); private: From 901d53cf703cb9a9de7b80627c01b287c9f950e7 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Wed, 17 Jun 2020 18:56:36 +0000 Subject: [PATCH 071/148] I2c_MultiTLVCodec: prevent copying --- include/I2c_MultiTLVCodec.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index d150037d9..522142833 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -45,6 +45,7 @@ class I2c_MultiTLVCodec : public AudioCodec int debugReadRegister(int codecNum, int regNum); McaspConfig& getMcaspConfig(); + I2c_MultiTLVCodec(I2c_MultiTLVCodec&&) = delete; I2c_MultiTLVCodec(std::vector i2cBusses, int i2cAddress, TdmConfig tdmConfig = TdmConfig(), bool verbose = false); ~I2c_MultiTLVCodec(); From 6a46033ee2b4167e810e5a150a7eec1a30a19241 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Wed, 17 Jun 2020 18:58:06 +0000 Subject: [PATCH 072/148] MultiTLVCodec: allow children classes to access mcaspConfig, also renamed and moved to constructor --- core/I2c_MultiTLVCodec.cpp | 17 ++++++++--------- include/I2c_MultiTLVCodec.h | 3 ++- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 4c13af8c9..9136b6a68 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -47,8 +47,6 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(std::vector i2cBusses, int i2 } // Master codec generates bclk (and possibly wclk) with its PLL // and occupies the first two slots starting from tdmConfig.firstSlot - const unsigned int slotSize = tdmConfig.slotSize; - const unsigned int bitDelay = tdmConfig.bitDelay; unsigned int slotNum = tdmConfig.firstSlot; bool codecWclkMaster = #ifdef CODEC_WCLK_MASTER @@ -58,8 +56,8 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(std::vector i2cBusses, int i2 #endif AudioCodecParams params; - params.slotSize = slotSize; - params.bitDelay = bitDelay; + params.slotSize = tdmConfig.slotSize; + params.bitDelay = tdmConfig.bitDelay; params.dualRate = false; params.tdmMode = true; params.startingSlot = slotNum; @@ -74,6 +72,11 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(std::vector i2cBusses, int i2 params.startingSlot = slotNum; codec->setParameters(params); } + // initialise the McASP configuration. + mcaspConfig = masterCodec->getMcaspConfig(); + mcaspConfig.params.dataSize = kDataSize; + mcaspConfig.params.inChannels = getNumIns(); + mcaspConfig.params.outChannels = getNumOuts(); } // This method initialises the audio codec to its default state @@ -278,11 +281,7 @@ I2c_MultiTLVCodec::~I2c_MultiTLVCodec() McaspConfig& I2c_MultiTLVCodec::getMcaspConfig() { - mc = masterCodec->getMcaspConfig(); - mc.params.dataSize = kDataSize; - mc.params.inChannels = getNumIns(); - mc.params.outChannels = getNumOuts(); - return mc; + return mcaspConfig; /* // Values below are for 16x 16-bit TDM slots #define BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index 522142833..73c3cda0d 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -49,10 +49,11 @@ class I2c_MultiTLVCodec : public AudioCodec I2c_MultiTLVCodec(std::vector i2cBusses, int i2cAddress, TdmConfig tdmConfig = TdmConfig(), bool verbose = false); ~I2c_MultiTLVCodec(); +protected: + McaspConfig mcaspConfig; private: I2c_Codec *masterCodec; std::vector extraCodecs; - McaspConfig mc; bool running; bool verbose; From a0d89c04849d9c0865570cf023d66d624af9f22e Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Wed, 17 Jun 2020 22:31:20 +0000 Subject: [PATCH 073/148] I2c_MultiTdmCodec: refactoring for multiple codecs. Now inheriting from I2c_MultiTLVCodec instead --- core/I2c_MultiTdmCodec.cpp | 34 ++++++++++++++++++++-------------- core/RTAudio.cpp | 2 +- include/I2c_MultiTdmCodec.h | 8 +++++--- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/core/I2c_MultiTdmCodec.cpp b/core/I2c_MultiTdmCodec.cpp index 76e270747..197e804af 100644 --- a/core/I2c_MultiTdmCodec.cpp +++ b/core/I2c_MultiTdmCodec.cpp @@ -1,33 +1,39 @@ #include "../include/I2c_MultiTdmCodec.h" -I2c_MultiTdmCodec::I2c_MultiTdmCodec(int i2cBus, int i2cAddress, bool isVerbose /*= false*/) : - I2c_Codec(i2cBus, i2cAddress, CodecType::TLV320AIC3104, isVerbose) +static const unsigned int minTdmIns = 4; +static const unsigned int minTdmOuts = 4; + +I2c_MultiTLVCodec::TdmConfig I2c_MultiTdmCodec::makeTdmConfig() +{ + I2c_MultiTLVCodec::TdmConfig tdm; + tdm.slotSize = 32; + tdm.bitDelay = 1; + tdm.firstSlot = 0; + return tdm; +} + +I2c_MultiTdmCodec::I2c_MultiTdmCodec(std::vector i2cBusses, int i2cAddress, bool isVerbose) + : I2c_MultiTLVCodec(i2cBusses, i2cAddress, makeTdmConfig(), isVerbose) { - params.slotSize = 32; - params.tdmMode = true; - params.startingSlot = 0; - params.bitDelay = 1; - params.dualRate = false; - params.generatesBclk = true; - params.generatesWclk = true; + I2c_MultiTLVCodec::getMcaspConfig(); + mcaspConfig.params.inSerializers = {0, 1}; } McaspConfig& I2c_MultiTdmCodec::getMcaspConfig() { - mcaspConfig = I2c_Codec::getMcaspConfig(); - mcaspConfig.params.dataSize = 16; mcaspConfig.params.inChannels = getNumIns(); mcaspConfig.params.outChannels = getNumOuts(); - mcaspConfig.params.inSerializers = {0, 1}; return mcaspConfig; } unsigned int I2c_MultiTdmCodec::getNumIns() { - return 8; + unsigned int mul = mcaspConfig.params.inSerializers.size(); + return std::max(I2c_MultiTLVCodec::getNumIns() * mul, minTdmIns * mul); } unsigned int I2c_MultiTdmCodec::getNumOuts() { - return 8; + unsigned int mul = mcaspConfig.params.outSerializers.size(); + return std::max(I2c_MultiTLVCodec::getNumOuts() * mul, minTdmOuts * mul); } diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index ef1917561..0d9ac591c 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -421,7 +421,7 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) else if(belaHw == BelaHw_BelaMiniMultiAudio) gAudioCodec = new I2c_MultiTLVCodec({codecI2cBus}, codecI2cAddress, {}, gRTAudioVerbose); else if(belaHw == BelaHw_BelaMiniMultiTdm) - gAudioCodec = new I2c_MultiTdmCodec(codecI2cBus, codecI2cAddress, gRTAudioVerbose); + gAudioCodec = new I2c_MultiTdmCodec({codecI2cBus, 1}, codecI2cAddress, gRTAudioVerbose); else if(Bela_hwContains(belaHw, Tlv320aic3104)) { gAudioCodec = new I2c_Codec(codecI2cBus, codecI2cAddress, I2c_Codec::TLV320AIC3104, gRTAudioVerbose); diff --git a/include/I2c_MultiTdmCodec.h b/include/I2c_MultiTdmCodec.h index 240024fd6..e739c564c 100644 --- a/include/I2c_MultiTdmCodec.h +++ b/include/I2c_MultiTdmCodec.h @@ -1,10 +1,12 @@ -#include "I2c_Codec.h" +#include "I2c_MultiTLVCodec.h" -class I2c_MultiTdmCodec : public I2c_Codec +class I2c_MultiTdmCodec : public I2c_MultiTLVCodec { public: - I2c_MultiTdmCodec(int i2cBus, int i2cAddress, bool isVerbose = false); + I2c_MultiTdmCodec(std::vector i2cBusses, int i2cAddress, bool isVerbose = false); unsigned int getNumIns() override; unsigned int getNumOuts() override; McaspConfig& getMcaspConfig() override; +private: + static I2c_MultiTLVCodec::TdmConfig makeTdmConfig(); }; From c106adddc1989d349fe2b1b098b3f0e3d5e3cb1f Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Thu, 18 Jun 2020 18:17:13 +0000 Subject: [PATCH 074/148] I2c_MultiTdmCodec: use two output serializers --- core/I2c_MultiTdmCodec.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/I2c_MultiTdmCodec.cpp b/core/I2c_MultiTdmCodec.cpp index 197e804af..12562ac62 100644 --- a/core/I2c_MultiTdmCodec.cpp +++ b/core/I2c_MultiTdmCodec.cpp @@ -1,7 +1,7 @@ #include "../include/I2c_MultiTdmCodec.h" -static const unsigned int minTdmIns = 4; -static const unsigned int minTdmOuts = 4; +static const unsigned int minTdmIns = 6; +static const unsigned int minTdmOuts = 6; I2c_MultiTLVCodec::TdmConfig I2c_MultiTdmCodec::makeTdmConfig() { @@ -17,6 +17,7 @@ I2c_MultiTdmCodec::I2c_MultiTdmCodec(std::vector i2cBusses, int i2 { I2c_MultiTLVCodec::getMcaspConfig(); mcaspConfig.params.inSerializers = {0, 1}; + mcaspConfig.params.outSerializers = {2, 3}; } McaspConfig& I2c_MultiTdmCodec::getMcaspConfig() From 6d41ce58e252116fdc14fd80d8c2592db60e1281 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 22 Jun 2020 16:03:48 +0000 Subject: [PATCH 075/148] Mcasp: added print() method --- core/Mcasp.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++++----- include/Mcasp.h | 1 + 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/core/Mcasp.cpp b/core/Mcasp.cpp index 52a92055e..c558ac870 100644 --- a/core/Mcasp.cpp +++ b/core/Mcasp.cpp @@ -426,10 +426,55 @@ McaspRegisters McaspConfig::getRegisters() return regs; } -#include - -void mcasp_test(const char* name, uint32_t val1, uint32_t val2) +#include +#include +// https://stackoverflow.com/questions/10750057/how-to-print-out-the-contents-of-a-vector +template +std::ostream& operator<< (std::ostream& out, const std::vector& v) { + if ( !v.empty() ) { + out << '{'; + std::copy (v.begin(), v.end(), std::ostream_iterator(out, ", ")); + out << "\b\b}"; + } + return out; +} +void McaspConfig::print() { - printf("mcasp %s %#10x %#10x %s\n", name, val1, val2, - val1 == val2 ? "SUCCESS" : "ERROR"); +#define P(FIELD) std::cout << #FIELD << ": " << params.FIELD << "\n" + std::cout << "Parameters:\n"; + P(inChannels); + P(outChannels); + P(inSerializers); + P(outSerializers); + P(numSlots); + P(slotSize); + P(dataSize); + P(bitDelay); + P(auxClkIn); + P(ahclkFreq); + P(ahclkIsInternal); + P(wclkIsInternal); + P(wclkIsWord); + P(wclkFalling); + P(externalRisingEdge); + + getRegisters(); // update the registers with the current parameters +#define R(FIELD) printf("%10s: 0x%08x\n", #FIELD, regs.FIELD) + printf("Registers:\n"); + R(pdir); + R(rmask); + R(rfmt); + R(afsrctl); + R(aclkrctl); + R(ahclkrctl); + R(rtdm); + R(xmask); + R(xfmt); + R(afsxctl); + R(aclkxctl); + R(ahclkxctl); + R(xtdm); + R(srctln); + R(wfifoctl); + R(rfifoctl); } diff --git a/include/Mcasp.h b/include/Mcasp.h index 25136efb4..099eb9a78 100644 --- a/include/Mcasp.h +++ b/include/Mcasp.h @@ -59,6 +59,7 @@ class McaspConfig } SrctlDrive; double getValidAhclk(double desiredClock, unsigned int* outDiv = nullptr); McaspConfig(); + void print(); Parameters params; McaspRegisters getRegisters(); private: From a49c989a08a146c46eac5f4e312360dd64b1b80a Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 22 Jun 2020 16:14:21 +0000 Subject: [PATCH 076/148] PRU: ensuring the input does not go out of sync by only reading if there is enough data available --- pru/pru_rtaudio_irq.p | 55 +++++++++++-------------------------------- 1 file changed, 14 insertions(+), 41 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 9993cd60c..f43c31603 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -1545,44 +1545,6 @@ WRITE_FRAME_DONE: MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 3) // Set RSMRST MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 11) // Set XSMRST -#ifdef ATTEMPT_TO_RESYNC_BELA_ADC -// for BELA_TLV32, the left and right channels are swapped, so that each frame contains: -//R[n-1], L[n]. -//something similar was happening in pru_rtaudio.p and the trick was to wait for -//one sample to come in and then discard it -//we try two approaches here, one based on the same solution as there, and one based on a hack, but none of them seems to work. - -//perform a write to avoid a TX underrun. This is just for testing, remove it -//later, as it would be adding latency and possibly causing offset of the -//outputs - MCASP_WRITE_TO_DATAPORT r8, 32 - // temporarily enable writes through the CFG port (if not already enabled) - // (note: datasheet does not say that changing this after the McASP has - // started would work, but it seems that it does) - MOV r2, BELA_TLV_MCASP_DATA_FORMAT_TX_VALUE // TODO: get this value by reading the register - MOV r3, r2 // back up the value - SET r2.t3 // set it to read from CFG port - MCASP_REG_WRITE MCASP_RFMT, r2 // Set data format -#ifdef ATTEMPT_TO_RESYNC_BELA_ADC_OLD_STYLE -MCASP_ADC_WAIT_BEFORE_LOOP: - LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4 - QBBC MCASP_ADC_WAIT_BEFORE_LOOP, r2, MCASP_RSTAT_RDATA_BIT - MCASP_REG_READ_EXT MCASP_RBUF, r2 // actually read and discard the value -#endif // ATTEMPT_TO_RESYNC_BELA_ADC_OLD_STYLE -#ifdef ATTEMPT_TO_RESYNC_BELA_ADC_HACK -/// wait for an actual non-zero value. Hopefully this would mean that one valid -// sample has been received from the codec - MOV r4, 0 -LOOPTHIS: - MCASP_REG_READ_EXT MCASP_RBUF, r2 // actually read and discard the value - QBNE DONELOOPTHIS, r2, 0 - ADD r4, r4, 1 - QBA LOOPTHIS -DONELOOPTHIS: -#endif // ATTEMPT_TO_RESYNC_BELA_ADC_HACK - MCASP_REG_WRITE MCASP_RFMT, r3 // Restore original value -#endif // ATTEMPT_TO_RESYNC_BELA_ADC - // 9. Release frame sync generators from reset. Note that it is necessary to // release the internal frame sync generators from reset, even if an external // frame sync is being used, because the frame sync error detection logic is built @@ -2018,13 +1980,24 @@ FRAME_READ_NOT_BELA_TLV32: QBGT FRAME_READ_MULTI_TLV_LT16CHAN, r0, 16 LDI r0, 16 FRAME_READ_MULTI_TLV_LT16CHAN: - LSL r0, r0, 1 // 16 bits per channel + // read from RFIFOSTS the number of words available to read + MCASP_REG_READ_EXT MCASP_RFIFOSTS, r27 + // Only start reading if all the words we need are available to read. + // This ensures we do not end up out of sync. + QBGT FRAME_READ_DONE, r27, r0 + + // one FIFO word is 32 bit. + // below we read two FIFO words at a time into r9 and r10 and then pack + // them as 16 bit words into r1 to (max) r8. This assumes the number of + // inputs is even. + + LSL r0, r0, 1 // r0 now contains the size in bytes of the packed data (16 bits per channel) - MCASP_READ_FROM_DATAPORT r9, 8 // TLVTODO: should this be 32 bytes like above? + MCASP_READ_FROM_DATAPORT r9, 8 AND r1, r9, r17 LSL r10, r10, 16 OR r1, r1, r10 - QBGE FRAME_READ_MULTI_TLV_STORE, r0, 4 // r0 = channels * 2 + QBGE FRAME_READ_MULTI_TLV_STORE, r0, 4 MCASP_READ_FROM_DATAPORT r9, 8 AND r2, r9, r17 From 7b635d5bbebf69dca1229a8420dc406128a49f76 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 22 Jun 2020 16:23:58 +0000 Subject: [PATCH 077/148] PRU: NOP. Refactoring source (no change in the generated code) --- pru/pru_rtaudio_irq.p | 68 +++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index f43c31603..a4539130d 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -1022,6 +1022,14 @@ GPIO_DONE: LBBO start_reg, r28, 0, num_bytes .endm +.macro FIFO_READ_2_WORDS_AND_PACK +.mparam reg_dest, reg_tmp1, reg_tmp2 + MCASP_READ_FROM_DATAPORT reg_tmp1, 8 + AND reg_dest, reg_tmp1, r17 + LSL reg_tmp2,reg_tmp2, 16 + OR reg_dest, reg_dest, reg_tmp2 +.endm + // Set a bit and wait for it to come up .macro MCASP_REG_SET_BIT_AND_POLL .mparam reg, mask @@ -1993,52 +2001,28 @@ FRAME_READ_MULTI_TLV_LT16CHAN: LSL r0, r0, 1 // r0 now contains the size in bytes of the packed data (16 bits per channel) - MCASP_READ_FROM_DATAPORT r9, 8 - AND r1, r9, r17 - LSL r10, r10, 16 - OR r1, r1, r10 + FIFO_READ_2_WORDS_AND_PACK r1, r9, r10 QBGE FRAME_READ_MULTI_TLV_STORE, r0, 4 - MCASP_READ_FROM_DATAPORT r9, 8 - AND r2, r9, r17 - LSL r10, r10, 16 - OR r2, r2, r10 - QBGE FRAME_READ_MULTI_TLV_STORE, r0, 8 - - MCASP_READ_FROM_DATAPORT r9, 8 - AND r3, r9, r17 - LSL r10, r10, 16 - OR r3, r3, r10 - QBGE FRAME_READ_MULTI_TLV_STORE, r0, 12 - - MCASP_READ_FROM_DATAPORT r9, 8 - AND r4, r9, r17 - LSL r10, r10, 16 - OR r4, r4, r10 - QBGE FRAME_READ_MULTI_TLV_STORE, r0, 16 - - MCASP_READ_FROM_DATAPORT r9, 8 - AND r5, r9, r17 - LSL r10, r10, 16 - OR r5, r5, r10 - QBGE FRAME_READ_MULTI_TLV_STORE, r0, 20 + FIFO_READ_2_WORDS_AND_PACK r2, r9, r10 + QBGE FRAME_READ_MULTI_TLV_STORE, r0, 8 + + FIFO_READ_2_WORDS_AND_PACK r3, r9, r10 + QBGE FRAME_READ_MULTI_TLV_STORE, r0, 12 + + FIFO_READ_2_WORDS_AND_PACK r4, r9, r10 + QBGE FRAME_READ_MULTI_TLV_STORE, r0, 16 + + FIFO_READ_2_WORDS_AND_PACK r5, r9, r10 + QBGE FRAME_READ_MULTI_TLV_STORE, r0, 20 - MCASP_READ_FROM_DATAPORT r9, 8 - AND r6, r9, r17 - LSL r10, r10, 16 - OR r6, r6, r10 - QBGE FRAME_READ_MULTI_TLV_STORE, r0, 24 - - MCASP_READ_FROM_DATAPORT r9, 8 - AND r7, r9, r17 - LSL r10, r10, 16 - OR r7, r7, r10 - QBGE FRAME_READ_MULTI_TLV_STORE, r0, 28 + FIFO_READ_2_WORDS_AND_PACK r6, r9, r10 + QBGE FRAME_READ_MULTI_TLV_STORE, r0, 24 + + FIFO_READ_2_WORDS_AND_PACK r7, r9, r10 + QBGE FRAME_READ_MULTI_TLV_STORE, r0, 28 - MCASP_READ_FROM_DATAPORT r9, 8 - AND r8, r9, r17 - LSL r10, r10, 16 - OR r8, r8, r10 + FIFO_READ_2_WORDS_AND_PACK r8, r9, r10 FRAME_READ_MULTI_TLV_STORE: SBCO r1, C_MCASP_MEM, reg_mcasp_adc_current, b0 // store result From c5a9b6a29351187c7af6db122cd9cbe0b4f82cb4 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 30 Jun 2020 14:33:21 +0000 Subject: [PATCH 078/148] I2c_CodeC: refactored noInit / noDeinit to minimise the number of parameters that are not affected (only those related to clocks) --- core/I2c_Codec.cpp | 211 ++++++++++++++++++++++----------------------- 1 file changed, 103 insertions(+), 108 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 03cce56d5..f119b3e5b 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -57,96 +57,12 @@ int I2c_Codec::initCodec() // See the TLV320AIC3106 datasheet for full details of the registers int I2c_Codec::startAudio(int dummy) { - if(InitMode_noInit == mode) - return 0; // As a best-practice it's safer not to assume the implementer has issued initCodec() // or has not otherwise modified codec registers since that call. // Explicit Switch to config register page 0: if(writeRegister(0x00, 0x00)) // Page Select Register return 1; - // see datasehet for TLV320AIC3104 from page 44 - if(writeRegister(0x02, 0x00)) // Codec sample rate register: fs_ref / 1 - return 1; - - if(params.generatesBclk) { - if(setAudioSamplingRate(44100)) - return 1; - } - else { - // Disable PLL: the codec will be clocked from the bit clock generated by another master - - if(writeRegister(0x03, 0x11)) // PLL disable, Q = 2 (fs = CLKIN / 256) - return 1; - } - - if(params.dualRate) { - if(writeRegister(0x07, 0xEA)) // Codec datapath register: 44.1kHz; dual rate; standard datapath - return 1; - } - else { - if(writeRegister(0x07, 0x8A)) // Codec datapath register: 44.1kHz; std rate; standard datapath - return 1; - } - - if(params.generatesBclk) { - if(params.generatesWclk) { - if(writeRegister(0x08, 0xE0)) { // Audio serial control register A: BCLK, WCLK outputs, - return 1; // DOUT tri-state when inactive - } - } - else { - if(writeRegister(0x08, 0xA0)) { // Audio serial control register A: BCLK output, WCLK input, - return 1; // DOUT tri-state when inactive - } - } - } - else { - // If we don't generate the bit clock then we don't generate the word clock - if(writeRegister(0x08, 0x20)) // Audio serial control register A: BCLK, WCLK inputs, - return 1; // DOUT tri-state when inactive - } - - if(params.tdmMode) { - // Supported values of slot size in the PRU code: 16 and 32 bits. Note that - // altering slot size requires changing #defines in the PRU code. - unsigned int crb; // Audio serial control register B - switch(params.slotSize) {// The below values all enable 256-clock mode when Bclk is an output - case 16: - crb = 0x48; - break; - case 20: - crb = 0x58; - break; - case 24: - crb = 0x68; - break; - case 32: - crb = 0x78; - break; - default: - return 1; - } - - if(writeRegister(0x09, crb)) // Audio serial control register B: DSP/TDM mode, word len specified by slotSize - return 1; - if(writeRegister(0x0A, params.startingSlot * params.slotSize + params.bitDelay)) // Audio serial control register C: specifying offset in bits - return 1; - } - else { -#ifdef TLV320_DSP_MODE // to use with old PRU code - if(writeRegister(0x09, 0x40)) // Audio serial control register B: DSP mode, word len 16 bits -#else - if(writeRegister(0x09, 0x00)) // Audio serial control register B: I2S mode, word len 16 bits -#endif - return 1; -#ifdef TLV320_DSP_MODE // to use with old PRU code - if(writeRegister(0x0A, 0x00)) // Audio serial control register C: 0 bit offset -#else - if(writeRegister(0x0A, 0x01)) // Audio serial control register C: 1 bit offset -#endif - return 1; - } if(writeRegister(0x0D, 0x00)) // Headset / button press register A: disabled return 1; if(writeRegister(0x0E, 0x00)) // Headset / button press register B: disabled @@ -165,14 +81,104 @@ int I2c_Codec::startAudio(int dummy) if(writeHPVolumeRegisters()) // Send DAC to high-power outputs return 1; - if(params.generatesBclk) { - if(writeRegister(0x66, 0x02)) // Clock generation control register: use MCLK, PLL N = 2 - return 1; - } - else { - if(writeRegister(0x66, 0x82)) // Clock generation control register: use BCLK, PLL N = 2 + + if(InitMode_noInit != mode) { + // see datasehet for TLV320AIC3104 from page 44 + if(writeRegister(0x02, 0x00)) // Codec sample rate register: fs_ref / 1 return 1; - } + + if(params.generatesBclk) { + if(setAudioSamplingRate(44100)) + return 1; + } + else { + // Disable PLL: the codec will be clocked from the bit clock generated by another master + if(writeRegister(0x03, 0x11)) // PLL disable, Q = 2 (fs = CLKIN / 256) + return 1; + } + + if(params.dualRate) { + if(writeRegister(0x07, 0xEA)) // Codec datapath register: 44.1kHz; dual rate; standard datapath + return 1; + } + else { + if(writeRegister(0x07, 0x8A)) // Codec datapath register: 44.1kHz; std rate; standard datapath + return 1; + } + + if(params.generatesBclk) { + if(params.generatesWclk) { + if(writeRegister(0x08, 0xE0)) { // Audio serial control register A: BCLK, WCLK outputs, + return 1; // DOUT tri-state when inactive + } + } + else { + if(writeRegister(0x08, 0xA0)) { // Audio serial control register A: BCLK output, WCLK input, + return 1; // DOUT tri-state when inactive + } + } + } + else { + // If we don't generate the bit clock then we don't generate the word clock + if(writeRegister(0x08, 0x20)) // Audio serial control register A: BCLK, WCLK inputs, + return 1; // DOUT tri-state when inactive + } + + if(params.tdmMode) { + // Supported values of slot size in the PRU code: 16 and 32 bits. Note that + // altering slot size requires changing #defines in the PRU code. + unsigned int crb; // Audio serial control register B + switch(params.slotSize) {// The below values all enable 256-clock mode when Bclk is an output + case 16: + crb = 0x48; + break; + case 20: + crb = 0x58; + break; + case 24: + crb = 0x68; + break; + case 32: + crb = 0x78; + break; + default: + return 1; + } + + if(writeRegister(0x09, crb)) // Audio serial control register B: DSP/TDM mode, word len specified by slotSize + return 1; + if(writeRegister(0x0A, params.startingSlot * params.slotSize + params.bitDelay)) // Audio serial control register C: specifying offset in bits + return 1; + } + else { +#ifdef TLV320_DSP_MODE // to use with old PRU code + if(writeRegister(0x09, 0x40)) // Audio serial control register B: DSP mode, word len 16 bits +#else + if(writeRegister(0x09, 0x00)) // Audio serial control register B: I2S mode, word len 16 bits +#endif + return 1; +#ifdef TLV320_DSP_MODE // to use with old PRU code + if(writeRegister(0x0A, 0x00)) // Audio serial control register C: 0 bit offset +#else + if(writeRegister(0x0A, 0x01)) // Audio serial control register C: 1 bit offset +#endif + return 1; + } + + // clock generation + if(params.generatesBclk) { + if(writeRegister(0x66, 0x02)) // Clock generation control register: use MCLK, PLL N = 2 + return 1; + if(writeRegister(0x65, 0x00)) // GPIO control register B: disabled; codec uses PLLDIV_OUT + return 1; + } + else { + if(writeRegister(0x66, 0x82)) // Clock generation control register: use BCLK, PLL N = 2 + return 1; + if(writeRegister(0x65, 0x01)) // GPIO control register B: disabled; codec uses CLKDIV_OUT + return 1; + } + } // if not noInit //Set-up hardware high-pass filter for DC removal if(codecType == TLV320AIC3104) { @@ -205,15 +211,6 @@ int I2c_Codec::startAudio(int dummy) if(writeDACVolumeRegisters(false)) // Unmute and set volume return 1; - if(params.generatesBclk) { - if(writeRegister(0x65, 0x00)) // GPIO control register B: disabled; codec uses PLLDIV_OUT - return 1; - } - else { - if(writeRegister(0x65, 0x01)) // GPIO control register B: disabled; codec uses CLKDIV_OUT - return 1; - } - if(writeADCVolumeRegisters(false)) // Unmute and set ADC volume return 1; @@ -672,8 +669,6 @@ int I2c_Codec::enableLineOut(bool enable) // This tells the codec to stop generating audio and mute the outputs int I2c_Codec::stopAudio() { - if(InitMode_noInit == mode || InitMode_noDeinit == mode) - return 0; if(writeDACVolumeRegisters(true)) // Mute the DACs return 1; if(writeADCVolumeRegisters(true)) // Mute the ADCs @@ -687,12 +682,12 @@ int I2c_Codec::stopAudio() return 1; if(enableLineOut(false)) return 1; - if(writeRegister(0x25, 0x00)) // DAC power/driver register: power off - return 1; - if(writeRegister(0x03, 0x11)) // PLL register A: disable - return 1; - //if(writeRegister(0x01, 0x80)) // Reset codec to defaults - // return 1; + if(InitMode_noInit != mode && InitMode_noDeinit != mode) { + if(writeRegister(0x25, 0x00)) // DAC power/driver register: power off. For whatever reason, executing this also turns off the BCLK output + return 1; + if(writeRegister(0x03, 0x11)) // PLL register A: disable + return 1; + } running = false; return 0; From c70a08c69e9559d36d3bbd17963f8abe572e1a4a Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 30 Jun 2020 15:07:01 +0000 Subject: [PATCH 079/148] I2c_MultiT*Codec: using a configuration string --- core/I2c_MultiTLVCodec.cpp | 135 +++++++++++++++++++++++++++++------- core/I2c_MultiTdmCodec.cpp | 5 +- core/RTAudio.cpp | 18 +++-- include/I2c_MultiTLVCodec.h | 2 +- include/I2c_MultiTdmCodec.h | 2 +- 5 files changed, 129 insertions(+), 33 deletions(-) diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 9136b6a68..be48f5f95 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -12,34 +12,121 @@ #include "../include/I2c_MultiTLVCodec.h" static const unsigned int kDataSize = 16; -#undef CODEC_WCLK_MASTER // Match this with pru_rtaudio_irq.p +#undef CODEC_WCLK_MASTER -I2c_MultiTLVCodec::I2c_MultiTLVCodec(std::vector i2cBusses, int i2cAddress, TdmConfig tdmConfig, bool isVerbose /*= false*/) +#include +#include +// duplicated from board_detect.cpp +static std::vector split(const std::string& s, char delimiter) +{ + std::vector tokens; + std::string token; + std::istringstream tokenStream(s); + while (std::getline(tokenStream, token, delimiter)) + { + tokens.push_back(token); + } + return tokens; +} + +static std::string trim(std::string const& str) +{ + if(str.empty()) + return str; + + std::size_t firstScan = str.find_first_not_of(' '); + std::size_t first = firstScan == std::string::npos ? str.length() : firstScan; + std::size_t last = str.find_last_not_of(' '); + return str.substr(first, last - first + 1); +} + +struct Address { + unsigned int bus; + uint8_t address; + I2c_Codec::CodecType type; + bool required; +}; + +static const std::map codecTypeMap = { + {"3104", I2c_Codec::TLV320AIC3104}, + {"3106", I2c_Codec::TLV320AIC3106}, +}; + +[[noreturn]] static void throwErr(std::string err, std::string token = "") +{ + throw std::runtime_error("I2c_MultiTLVCodec: " + err + (token != "" ? "`" + token : "") + "`\n"); +} + +static I2c_Codec::CodecType getCodecTypeFromString(const std::string& str) +{ + try { + return codecTypeMap.at(trim(str)); + } catch(std::exception e) { + throwErr("Unrecognised codec type", str); + } +} + +I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdmConfig, bool isVerbose) : masterCodec(0), running(false), verbose(isVerbose) { - for(auto i2cBus : i2cBusses) { - for(int address = i2cAddress; address < i2cAddress + 4; address++) { - // Check for presence of TLV codec and take the first one we find as the master codec - // TODO: this code assumes the first codec is a 3104 (Bela Mini cape), which might not always be true - I2c_Codec::CodecType type = (address == i2cAddress) ? I2c_Codec::TLV320AIC3104 : I2c_Codec::TLV320AIC3106; - I2c_Codec *testCodec = new I2c_Codec(i2cBus, address, type); - if(testCodec->initCodec() != 0) { - delete testCodec; - if(verbose) { - fprintf(stderr, "Error initialising I2C codec on bus %d address %d\n", i2cBus, address); - } - } - else { - // codec found - if(verbose) { - fprintf(stderr, "Found I2C codec on bus %d address %d\n", i2cBus, address); - } - - if(!masterCodec) - masterCodec = testCodec; - else - extraCodecs.push_back(testCodec); + std::vector
addresses; + std::vector tokens = split(cfgString, ';'); + if(tokens.size() < 1) + throwErr("Wrong format for cfgString ", cfgString); + if("" == trim(tokens.back())) + tokens.pop_back(); + std::string mode; + for(auto& token: tokens) { + // the string will contain semicolon-separated label:value pairs + // ADDR: ,,, + // MODE: + // e.g.: ADDR: 2,24,3104,1;ADDR: 1,24,3106,0;MODE: noInit + std::vector tks = split(token, ':'); + if(tks.size() != 2) + throwErr("Wrong format for token ", token); + if("ADDR" == trim(tks[0])) { + std::vector ts = split(tks[1], ','); + if(ts.size() != 4) + throwErr("Wrong format for argument", tks[1]); + addresses.push_back({ + .bus = (unsigned int)std::stoi(ts[0]), + .address = (uint8_t)std::stoi(ts[1]), + .type = getCodecTypeFromString(ts[2]), + .required = (bool)std::stoi(ts[3]), + }); + } else if("MODE" == trim(tks[0]) && "" == mode) { + mode = trim(tks[1]); + } else { + throwErr("Unknown token ", token); + } + } + + for(auto& addr : addresses) { + unsigned int i2cBus = addr.bus; + uint8_t address = addr.address; + I2c_Codec::CodecType type = addr.type; + bool required = addr.required; + // Check for presence of TLV codec and take the first one we find as the master codec + I2c_Codec *testCodec = new I2c_Codec(i2cBus, address, type); + testCodec->setMode(mode); + if(testCodec->initCodec() != 0) { + delete testCodec; + std::string err = "Codec requested but not found at: " + std::to_string(i2cBus) + ", " + std::to_string(address) + ", " + std::to_string(type) + "\n"; + if(required) + throwErr(err); + if(verbose) + fprintf(stderr, "%s", err.c_str()); + } + else { + // codec found + if(verbose) { + fprintf(stderr, "Found I2C codec on bus %d address %d\n", i2cBus, address); } + + if(!masterCodec) + masterCodec = testCodec; + else + extraCodecs.push_back(testCodec); } } if(!masterCodec) { diff --git a/core/I2c_MultiTdmCodec.cpp b/core/I2c_MultiTdmCodec.cpp index 12562ac62..0b8796fee 100644 --- a/core/I2c_MultiTdmCodec.cpp +++ b/core/I2c_MultiTdmCodec.cpp @@ -12,8 +12,8 @@ I2c_MultiTLVCodec::TdmConfig I2c_MultiTdmCodec::makeTdmConfig() return tdm; } -I2c_MultiTdmCodec::I2c_MultiTdmCodec(std::vector i2cBusses, int i2cAddress, bool isVerbose) - : I2c_MultiTLVCodec(i2cBusses, i2cAddress, makeTdmConfig(), isVerbose) +I2c_MultiTdmCodec::I2c_MultiTdmCodec(const std::string& cfgString, bool isVerbose) + : I2c_MultiTLVCodec(cfgString, makeTdmConfig(), isVerbose) { I2c_MultiTLVCodec::getMcaspConfig(); mcaspConfig.params.inSerializers = {0, 1}; @@ -24,6 +24,7 @@ McaspConfig& I2c_MultiTdmCodec::getMcaspConfig() { mcaspConfig.params.inChannels = getNumIns(); mcaspConfig.params.outChannels = getNumOuts(); + mcaspConfig.params.wclkIsInternal = false; return mcaspConfig; } diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 0d9ac591c..283d90cad 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -407,6 +407,9 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) return 1; } + std::string codecMode; + if(settings->codecMode) + codecMode = settings->codecMode; // figure out which codec to use and which to disable if several are present and conflicting unsigned int ctags; if((ctags = Bela_hwContains(belaHw, CtagCape))) @@ -418,10 +421,14 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) if(Bela_hwContains(actualHw, Tlv320aic3104)) gDisabledCodec = new I2c_Codec(codecI2cBus, codecI2cAddress, I2c_Codec::TLV320AIC3104, gRTAudioVerbose); } - else if(belaHw == BelaHw_BelaMiniMultiAudio) - gAudioCodec = new I2c_MultiTLVCodec({codecI2cBus}, codecI2cAddress, {}, gRTAudioVerbose); + else if(belaHw == BelaHw_BelaMiniMultiAudio) { + std::string mode; + if("" != codecMode) + mode = "MODE:"+codecMode; + gAudioCodec = new I2c_MultiTLVCodec("ADDR:2,24,3104,0;ADDR:2,25,3106,0;ADDR:2,26,3106,0;ADDR:2,27,3106,0;"+mode, {}, gRTAudioVerbose); + } else if(belaHw == BelaHw_BelaMiniMultiTdm) - gAudioCodec = new I2c_MultiTdmCodec({codecI2cBus, 1}, codecI2cAddress, gRTAudioVerbose); + gAudioCodec = new I2c_MultiTdmCodec(codecMode, gRTAudioVerbose); else if(Bela_hwContains(belaHw, Tlv320aic3104)) { gAudioCodec = new I2c_Codec(codecI2cBus, codecI2cAddress, I2c_Codec::TLV320AIC3104, gRTAudioVerbose); @@ -434,8 +441,9 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) fprintf(stderr, "Error: invalid combinations of selected and available hardware\n"); return 1; } - if(settings->codecMode) - gAudioCodec->setMode(settings->codecMode); + // note: for some of the codecs, codecMode may have been + // been used above and/or this may be a NOP + gAudioCodec->setMode(codecMode); BelaHwConfig cfg = {0}; BelaHwConfigPrivate pcfg; diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index 73c3cda0d..6ab590487 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -46,7 +46,7 @@ class I2c_MultiTLVCodec : public AudioCodec McaspConfig& getMcaspConfig(); I2c_MultiTLVCodec(I2c_MultiTLVCodec&&) = delete; - I2c_MultiTLVCodec(std::vector i2cBusses, int i2cAddress, TdmConfig tdmConfig = TdmConfig(), bool verbose = false); + I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdmConfig = TdmConfig(), bool isVerbose = false); ~I2c_MultiTLVCodec(); protected: diff --git a/include/I2c_MultiTdmCodec.h b/include/I2c_MultiTdmCodec.h index e739c564c..2f3df5be1 100644 --- a/include/I2c_MultiTdmCodec.h +++ b/include/I2c_MultiTdmCodec.h @@ -3,7 +3,7 @@ class I2c_MultiTdmCodec : public I2c_MultiTLVCodec { public: - I2c_MultiTdmCodec(std::vector i2cBusses, int i2cAddress, bool isVerbose = false); + I2c_MultiTdmCodec(const std::string& cfgString, bool isVerbose = false); unsigned int getNumIns() override; unsigned int getNumOuts() override; McaspConfig& getMcaspConfig() override; From d23ecb96e5c523ef391a2d857917f0953830b6ac Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 30 Jun 2020 16:36:49 +0000 Subject: [PATCH 080/148] board_detect: fixed docs --- include/Bela.h | 44 ++++++++++++++------------- resources/tools/board_detect/main.cpp | 7 +++-- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/include/Bela.h b/include/Bela.h index 83c900507..672842644 100644 --- a/include/Bela.h +++ b/include/Bela.h @@ -80,18 +80,21 @@ int rt_fprintf(FILE *stream, const char *format, ...); int rt_vprintf(const char *format, va_list ap); int rt_vfprintf(FILE *stream, const char *format, va_list ap); +/** + * A type of Bela hardware. + */ typedef enum { - BelaHw_NoHw = -1, - BelaHw_Bela, - BelaHw_BelaMini, - BelaHw_Salt, - BelaHw_CtagFace, - BelaHw_CtagBeast, - BelaHw_CtagFaceBela, - BelaHw_CtagBeastBela, - BelaHw_BelaMiniMultiAudio, - BelaHw_BelaMiniMultiTdm, + BelaHw_NoHw = -1, ///< No hardware + BelaHw_Bela, ///< Bela + BelaHw_BelaMini, ///< Bela Mini + BelaHw_Salt, ///< Salt + BelaHw_CtagFace, ///< Ctag Face + BelaHw_CtagBeast, ///< Ctag Beast + BelaHw_CtagFaceBela, ///< Ctag Face and Bela cape + BelaHw_CtagBeastBela, ///< Ctag Beast and Bela cape + BelaHw_BelaMiniMultiAudio, ///< Bela Mini with extra codecs + BelaHw_BelaMiniMultiTdm, ///< Bela Mini with extra codes and tdm devices } BelaHw; typedef struct _BelaHwConfig @@ -117,13 +120,16 @@ BelaHwConfig* Bela_HwConfig_new(BelaHw hw); */ void Bela_HwConfig_delete(BelaHwConfig* cfg); +/** + * Arguments to be passed to Bela_detectHw() + */ typedef enum { - BelaHwDetectMode_Scan, - BelaHwDetectMode_Cache, - BelaHwDetectMode_CacheOnly, - BelaHwDetectMode_User, - BelaHwDetectMode_UserOnly, + BelaHwDetectMode_Scan, ///< perform an automatic detection by scanning the peripherals and busses available, and cache value in `/run/bela/belaconfig` + BelaHwDetectMode_Cache, ///< read cached value from `/run/bela/belaconfig` first. If it does not exist, fall back to #BelaHwDetectMode_Scan + BelaHwDetectMode_CacheOnly, /// @@ -698,12 +704,8 @@ void Bela_setVerboseLevel(int level); /** * \brief Detect what hardware we are running on. * - * \param mode How to perform the detection. Possible values are: - * BelaHwDetect_Scan : perform an automatic detection by scanning the peripherals and busses available, and cache value in `/run/bela/` - * BelaHwDetect_Cache: read cached value from `/run/bela` first. If it does not exist, fall back to BelaHwDetect_Scan - * BelaHwDetect_CacheOnly: read cached value from `/run/bela`. If it does not exist, return BelaHw_NoHw - * BelaHwDetect_User: read user-specified value from `~/.bela`. If it does not exist, fall back to BelaHwDetect_Cache - * BelaHwDetect_UserOnly: read user-specified value from `~/.bela`. If it does not exist, return BelaHw_NoHw + * + * \param mode How to perform the detection. The behaviour is described in #BelaHwDetectMode. */ BelaHw Bela_detectHw(BelaHwDetectMode mode); diff --git a/resources/tools/board_detect/main.cpp b/resources/tools/board_detect/main.cpp index d882be942..1b0b5b606 100644 --- a/resources/tools/board_detect/main.cpp +++ b/resources/tools/board_detect/main.cpp @@ -11,12 +11,13 @@ static void printHelp(const char* command) " %s \n" "Where is one of:\n" " scan\n" - " scanWithCache\n" + " cache\n" + " cacheOnly\n" " user (default)\n" " userOnly\n" - " full\n" + " all\n" " help\n" - "Each of these (except for `help' and `full') has the same role as the corresponding argument to `Bela_detectHw()' (see `Bela.h' for details). `full' performs each of the others in turn and prints all of the results in order\n", command); + "Each of these (except for `help' and `all') has the same role as the corresponding argument to `Bela_detectHw()' (see `Bela.h' for details). `all' performs each of the others in turn and prints all of the results in order\n", command); } From f14ebf426da8461fc645b567978ba5f2337481fa Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 20 Jul 2020 18:19:41 +0000 Subject: [PATCH 081/148] I2c_MultiTLVCodec: factored common code out to MiscUtilities --- core/I2c_MultiTLVCodec.cpp | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index be48f5f95..61a7ac5d3 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -10,36 +10,13 @@ #include #include "../include/I2c_MultiTLVCodec.h" +#include +#include "../include/MiscUtilities.h" +using namespace StringUtils; static const unsigned int kDataSize = 16; #undef CODEC_WCLK_MASTER -#include -#include -// duplicated from board_detect.cpp -static std::vector split(const std::string& s, char delimiter) -{ - std::vector tokens; - std::string token; - std::istringstream tokenStream(s); - while (std::getline(tokenStream, token, delimiter)) - { - tokens.push_back(token); - } - return tokens; -} - -static std::string trim(std::string const& str) -{ - if(str.empty()) - return str; - - std::size_t firstScan = str.find_first_not_of(' '); - std::size_t first = firstScan == std::string::npos ? str.length() : firstScan; - std::size_t last = str.find_last_not_of(' '); - return str.substr(first, last - first + 1); -} - struct Address { unsigned int bus; uint8_t address; From 9c7605572900672ab3f5edd41fb6ff0f8ef43537 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 20 Jul 2020 18:19:54 +0000 Subject: [PATCH 082/148] board_detect: factored common code out to MiscUtilities --- core/board_detect.cpp | 77 +++++---------------------- resources/tools/board_detect/Makefile | 2 +- 2 files changed, 14 insertions(+), 65 deletions(-) diff --git a/core/board_detect.cpp b/core/board_detect.cpp index 21b0a3343..4e1770c23 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -1,15 +1,13 @@ #include #include #include "../include/Bela.h" -#include -#include -#include #include #include #include "../include/I2c_Codec.h" #include "../include/Spi_Codec.h" #include "../include/bela_hw_settings.h" #include "../include/board_detect.h" +#include "../include/MiscUtilities.h" static const std::map belaHwMap = { {"NoHardware", BelaHw_NoHw}, @@ -48,29 +46,6 @@ static int is_belamini(){ return 0; } -static std::vector split(const std::string& s, char delimiter) -{ - std::vector tokens; - std::string token; - std::istringstream tokenStream(s); - while (std::getline(tokenStream, token, delimiter)) - { - tokens.push_back(token); - } - return tokens; -} - -static std::string trim(std::string const& str) -{ - if(str.empty()) - return str; - - std::size_t firstScan = str.find_first_not_of(' '); - std::size_t first = firstScan == std::string::npos ? str.length() : firstScan; - std::size_t last = str.find_last_not_of(' '); - return str.substr(first, last - first + 1); -} - // Returns true if the Tlv32 codec is detected // Returns false if the Tlv32 codec is not detected static bool detectTlv32(int bus, int address) @@ -129,46 +104,20 @@ std::string getBelaHwName(const BelaHw hardware) return noHw; } -static BelaHw parse_config_file(std::string path, std::string searchStr) +static BelaHw read_hw_from_file(const std::string& path, const std::string& searchStr) { - std::ifstream inputFile; - std::string line; - inputFile.open(path.c_str()); - if(!inputFile.fail()) - { - while (std::getline(inputFile, line)) - { - auto vec = split(line, '='); - if(vec.size() != 2) - continue; - if(trim(vec[0]) == searchStr) - { - std::string board = trim(vec[1]); - BelaHw hw = getBelaHw(board); - if(hw != BelaHw_NoHw) - return hw; - else - fprintf(stderr, "Unknown setting %s= in %s: %s. Ignoring.\n", searchStr.c_str(), path.c_str(), board.c_str()); - } - } - inputFile.close(); - } + std::string board = IoUtils::ConfigFile::readValue(path, searchStr); + BelaHw hw = getBelaHw(board); + if(hw != BelaHw_NoHw) + return hw; + else + fprintf(stderr, "Unknown setting %s= in %s: %s. Ignoring.\n", searchStr.c_str(), path.c_str(), board.c_str()); return BelaHw_NoHw; } -static int write_config_file(std::string path, BelaHw hardware) +static int write_hw_to_file(std::string path, BelaHw hardware) { - std::ofstream outputFile; - system(("bash -c \"mkdir -p `dirname "+path+"`\"").c_str()); - outputFile.open(path.c_str()); - if(outputFile.is_open()) - { - outputFile << "HARDWARE=" << getBelaHwName(hardware); - outputFile.close(); - return 0; - } - fprintf(stderr, "File %s could not be opened\n.", path.c_str()); - return -1; + return IoUtils::ConfigFile::writeValue(path, "HARDWARE", getBelaHwName(hardware)); } BelaHw Bela_detectHw(const BelaHwDetectMode mode) @@ -176,7 +125,7 @@ BelaHw Bela_detectHw(const BelaHwDetectMode mode) if(BelaHwDetectMode_User == mode || BelaHwDetectMode_UserOnly == mode) { std::string configPath = "/root/.bela/belaconfig"; - BelaHw hw = parse_config_file(configPath, "BOARD"); + BelaHw hw = read_hw_from_file(configPath, "BOARD"); if(hw != BelaHw_NoHw) return hw; if(BelaHwDetectMode_UserOnly == mode) @@ -188,7 +137,7 @@ BelaHw Bela_detectHw(const BelaHwDetectMode mode) std::string configPath = "/run/bela/belaconfig"; if(BelaHwDetectMode_Cache == mode || BelaHwDetectMode_CacheOnly == mode) { - BelaHw hw = parse_config_file(configPath, "HARDWARE"); + BelaHw hw = read_hw_from_file(configPath, "HARDWARE"); if(hw != BelaHw_NoHw) return hw; if(BelaHwDetectMode_CacheOnly == mode) @@ -236,7 +185,7 @@ BelaHw Bela_detectHw(const BelaHwDetectMode mode) } } if(hw != BelaHw_NoHw) - write_config_file(configPath, hw); + write_hw_to_file(configPath, hw); return hw; } diff --git a/resources/tools/board_detect/Makefile b/resources/tools/board_detect/Makefile index 3413c9e9b..3aab9bf9a 100644 --- a/resources/tools/board_detect/Makefile +++ b/resources/tools/board_detect/Makefile @@ -2,7 +2,7 @@ CXX=g++ CXXFLAGS=-std=c++11 BUILD=build $(shell mkdir -p build) -OBJS = $(BUILD)/GPIOcontrol.o $(BUILD)/Spi_Codec.o $(BUILD)/I2c_Codec.o $(BUILD)/I2c_MultiTLVCodec.o $(BUILD)/board_detect.o $(BUILD)/main.o $(BUILD)/Mcasp.o +OBJS = $(BUILD)/GPIOcontrol.o $(BUILD)/Spi_Codec.o $(BUILD)/I2c_Codec.o $(BUILD)/I2c_MultiTLVCodec.o $(BUILD)/MiscUtilities.o $(BUILD)/board_detect.o $(BUILD)/main.o $(BUILD)/Mcasp.o CPPFLAGS=-I../../../include From 7f88d8945b5958194a26308daa37209fcdd5f2da Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 17 Jul 2020 18:31:31 +0000 Subject: [PATCH 083/148] board_detect: use bela_sw_settings instead of hardcoded paths --- core/board_detect.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/board_detect.cpp b/core/board_detect.cpp index 4e1770c23..f4c9ddca1 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -6,6 +6,7 @@ #include "../include/I2c_Codec.h" #include "../include/Spi_Codec.h" #include "../include/bela_hw_settings.h" +#include "../include/bela_sw_settings.h" #include "../include/board_detect.h" #include "../include/MiscUtilities.h" @@ -124,8 +125,7 @@ BelaHw Bela_detectHw(const BelaHwDetectMode mode) { if(BelaHwDetectMode_User == mode || BelaHwDetectMode_UserOnly == mode) { - std::string configPath = "/root/.bela/belaconfig"; - BelaHw hw = read_hw_from_file(configPath, "BOARD"); + BelaHw hw = read_hw_from_file(userBelaConfig, "BOARD"); if(hw != BelaHw_NoHw) return hw; if(BelaHwDetectMode_UserOnly == mode) @@ -134,10 +134,9 @@ BelaHw Bela_detectHw(const BelaHwDetectMode mode) return Bela_detectHw(BelaHwDetectMode_Cache); } - std::string configPath = "/run/bela/belaconfig"; if(BelaHwDetectMode_Cache == mode || BelaHwDetectMode_CacheOnly == mode) { - BelaHw hw = read_hw_from_file(configPath, "HARDWARE"); + BelaHw hw = read_hw_from_file(sysBelaConfig, "HARDWARE"); if(hw != BelaHw_NoHw) return hw; if(BelaHwDetectMode_CacheOnly == mode) @@ -185,7 +184,7 @@ BelaHw Bela_detectHw(const BelaHwDetectMode mode) } } if(hw != BelaHw_NoHw) - write_hw_to_file(configPath, hw); + write_hw_to_file(sysBelaConfig, hw); return hw; } From 4d6cf2785481b908ac73dc6904ad2fcdc255fbcf Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 30 Jun 2020 18:31:04 +0000 Subject: [PATCH 084/148] RTAudio: CODEC_MODE can be picked up from belaconfig --- core/RTAudio.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 283d90cad..bbc733221 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -26,8 +26,10 @@ #include "../include/Bela.h" #include "../include/bela_hw_settings.h" +#include "../include/bela_sw_settings.h" #include "../include/board_detect.h" #include "../include/BelaContextFifo.h" +#include "../include/MiscUtilities.h" // Xenomai-specific includes #if XENOMAI_MAJOR == 3 @@ -410,6 +412,9 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) std::string codecMode; if(settings->codecMode) codecMode = settings->codecMode; + else + codecMode = IoUtils::ConfigFile::readValue(userBelaConfig, "CODEC_MODE"); + // figure out which codec to use and which to disable if several are present and conflicting unsigned int ctags; if((ctags = Bela_hwContains(belaHw, CtagCape))) From 27db2603a3808a07afcad429503711dfc1c2897c Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 20 Jul 2020 18:22:19 +0000 Subject: [PATCH 085/148] RTAudio: updated to take advantage of the MiscUtilities features --- core/RTAudio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index bbc733221..622150b41 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -413,7 +413,7 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) if(settings->codecMode) codecMode = settings->codecMode; else - codecMode = IoUtils::ConfigFile::readValue(userBelaConfig, "CODEC_MODE"); + codecMode = ConfigFileUtils::readValue(userBelaConfig, "CODEC_MODE"); // figure out which codec to use and which to disable if several are present and conflicting unsigned int ctags; From 509f72f180df254942c04ca79c80ee00ff83185d Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 20 Jul 2020 18:22:52 +0000 Subject: [PATCH 086/148] board_detect: updated to take advantage of the MiscUtilities --- core/board_detect.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/board_detect.cpp b/core/board_detect.cpp index f4c9ddca1..0189909ba 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -107,7 +107,7 @@ std::string getBelaHwName(const BelaHw hardware) static BelaHw read_hw_from_file(const std::string& path, const std::string& searchStr) { - std::string board = IoUtils::ConfigFile::readValue(path, searchStr); + std::string board = ConfigFileUtils::readValue(path, searchStr); BelaHw hw = getBelaHw(board); if(hw != BelaHw_NoHw) return hw; @@ -118,7 +118,7 @@ static BelaHw read_hw_from_file(const std::string& path, const std::string& sear static int write_hw_to_file(std::string path, BelaHw hardware) { - return IoUtils::ConfigFile::writeValue(path, "HARDWARE", getBelaHwName(hardware)); + return ConfigFileUtils::writeValue(path, "HARDWARE", getBelaHwName(hardware)); } BelaHw Bela_detectHw(const BelaHwDetectMode mode) From 3a0debabb36683a6a86ea09db6c6d9c783f2db35 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Thu, 2 Jul 2020 18:50:16 +0000 Subject: [PATCH 087/148] RTAudio.cpp: no longer accepts CODEC_MODE= in belaconfig: use CL="--codec-mode ..." instead to pass it. --- core/RTAudio.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 622150b41..9da1dff96 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -412,8 +412,6 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) std::string codecMode; if(settings->codecMode) codecMode = settings->codecMode; - else - codecMode = ConfigFileUtils::readValue(userBelaConfig, "CODEC_MODE"); // figure out which codec to use and which to disable if several are present and conflicting unsigned int ctags; From 89def20b2d320887494ac7208dc69b3a37f760ce Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 17 Jul 2020 18:15:23 +0000 Subject: [PATCH 088/148] PRU: removed a couple more defines --- core/PRU.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/PRU.cpp b/core/PRU.cpp index a382cf422..bc38a15db 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -188,8 +188,8 @@ class PruMemory static unsigned int* gDigitalPins = NULL; -#define USERLED3_GPIO_BASE (Gpio::getBankAddress(1))// GPIO1(24) is user LED 3 -#define USERLED3_PIN_MASK (1 << 24) +const uint32_t userLed3GpioBase = Gpio::getBankAddress(1); +const uint32_t userLed3GpioPinMask = 1 << 24; const unsigned int belaMiniLedBlue = 87; const uint32_t belaMiniLedBlueGpioBase = Gpio::getBankAddress(2); // GPIO2(23) is BelaMini LED blue const uint32_t belaMiniLedBlueGpioPinMask = 1 << 23; @@ -624,8 +624,8 @@ void PRU::initialisePruCommon(const McaspRegisters& mcaspRegisters) pru_buffer_comm[PRU_COMM_LED_ADDRESS] = belaMiniLedBlueGpioBase; pru_buffer_comm[PRU_COMM_LED_PIN_MASK] = belaMiniLedBlueGpioPinMask; } else { - pru_buffer_comm[PRU_COMM_LED_ADDRESS] = USERLED3_GPIO_BASE; - pru_buffer_comm[PRU_COMM_LED_PIN_MASK] = USERLED3_PIN_MASK; + pru_buffer_comm[PRU_COMM_LED_ADDRESS] = userLed3GpioBase; + pru_buffer_comm[PRU_COMM_LED_PIN_MASK] = userLed3GpioPinMask; } } else { From baaa33415819d07d2d5084889806ec80446fadc1 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 3 Jul 2020 16:15:07 +0000 Subject: [PATCH 089/148] I2c_Codec: fixed comments --- core/I2c_Codec.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index f119b3e5b..ea4dd3033 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -588,16 +588,17 @@ int I2c_Codec::writeADCVolumeRegisters(bool mute) return 1; if(codecType == TLV320AIC3106) { - // Configure inputs as fully differential, weak biasing - if(writeRegister(0x14, (volumeBits << 3) | 0x84)) // Line2L connected to left ADC + // Configure inputs as fully differential, weak biasing. + // LINE2L/R connected to corresponding L/R ADC PGA mix with specified gain. + if(writeRegister(0x14, (volumeBits << 3) | 0x84)) return 1; - if(writeRegister(0x17, (volumeBits << 3) | 0x84)) // Line2R connected to right ADC + if(writeRegister(0x17, (volumeBits << 3) | 0x84)) return 1; } else { // TLV320AIC3104 - if(writeRegister(0x11, (volumeBits << 4) | 0x0F)) // Line2L connected to left ADC + if(writeRegister(0x11, (volumeBits << 4) | 0x0F)) // Mic2L (sic) Input connected connected to left-ADC PGA mix with specified gain return 1; - if(writeRegister(0x12, volumeBits | 0xF0)) // Line2R connected to right ADC + if(writeRegister(0x12, volumeBits | 0xF0)) // Mic2R/Line2R connected to right-ADC PGA mix with specified gain return 1; } } From fc0a4fa5de47fba8ac703c2bacc99df513e04a8c Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 14 Jul 2020 16:11:48 +0000 Subject: [PATCH 090/148] I2c_MultiTLVCodec: allow to disable codecs --- core/I2c_MultiTLVCodec.cpp | 23 +++++++++++++++-------- core/RTAudio.cpp | 2 +- include/I2c_MultiTLVCodec.h | 1 + 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 61a7ac5d3..6127b5010 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -21,7 +21,7 @@ struct Address { unsigned int bus; uint8_t address; I2c_Codec::CodecType type; - bool required; + std::string required; }; static const std::map codecTypeMap = { @@ -56,8 +56,12 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm for(auto& token: tokens) { // the string will contain semicolon-separated label:value pairs // ADDR: ,,, + // (where "required" can be: + // - `r` equired + // - `n` ot required + // - `d` isabled // MODE: - // e.g.: ADDR: 2,24,3104,1;ADDR: 1,24,3106,0;MODE: noInit + // e.g.: ADDR: 2,24,3104,r;ADDR: 1,24,3106,o;MODE: noInit std::vector tks = split(token, ':'); if(tks.size() != 2) throwErr("Wrong format for token ", token); @@ -69,7 +73,7 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm .bus = (unsigned int)std::stoi(ts[0]), .address = (uint8_t)std::stoi(ts[1]), .type = getCodecTypeFromString(ts[2]), - .required = (bool)std::stoi(ts[3]), + .required = trim(ts[3]), }); } else if("MODE" == trim(tks[0]) && "" == mode) { mode = trim(tks[1]); @@ -82,14 +86,14 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm unsigned int i2cBus = addr.bus; uint8_t address = addr.address; I2c_Codec::CodecType type = addr.type; - bool required = addr.required; + std::string required = addr.required; // Check for presence of TLV codec and take the first one we find as the master codec I2c_Codec *testCodec = new I2c_Codec(i2cBus, address, type); testCodec->setMode(mode); if(testCodec->initCodec() != 0) { delete testCodec; std::string err = "Codec requested but not found at: " + std::to_string(i2cBus) + ", " + std::to_string(address) + ", " + std::to_string(type) + "\n"; - if(required) + if("r" == required) throwErr(err); if(verbose) fprintf(stderr, "%s", err.c_str()); @@ -97,10 +101,11 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm else { // codec found if(verbose) { - fprintf(stderr, "Found I2C codec on bus %d address %d\n", i2cBus, address); + fprintf(stderr, "Found I2C codec on bus %d address %d, required: %s\n", i2cBus, address, required.c_str()); } - - if(!masterCodec) + if("d" == required) + disabledCodecs.push_back(testCodec); + else if(!masterCodec) masterCodec = testCodec; else extraCodecs.push_back(testCodec); @@ -341,6 +346,8 @@ I2c_MultiTLVCodec::~I2c_MultiTLVCodec() delete *it; if(masterCodec) delete masterCodec; + for(it = disabledCodecs.begin(); it != disabledCodecs.end(); ++it) + delete *it; } McaspConfig& I2c_MultiTLVCodec::getMcaspConfig() diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 9da1dff96..3b8f6e58f 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -428,7 +428,7 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) std::string mode; if("" != codecMode) mode = "MODE:"+codecMode; - gAudioCodec = new I2c_MultiTLVCodec("ADDR:2,24,3104,0;ADDR:2,25,3106,0;ADDR:2,26,3106,0;ADDR:2,27,3106,0;"+mode, {}, gRTAudioVerbose); + gAudioCodec = new I2c_MultiTLVCodec("ADDR:2,24,3104,n;ADDR:2,25,3106,n;ADDR:2,26,3106,n;ADDR:2,27,3106,n;"+mode, {}, gRTAudioVerbose); } else if(belaHw == BelaHw_BelaMiniMultiTdm) gAudioCodec = new I2c_MultiTdmCodec(codecMode, gRTAudioVerbose); diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index 6ab590487..b62425cd3 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -54,6 +54,7 @@ class I2c_MultiTLVCodec : public AudioCodec private: I2c_Codec *masterCodec; std::vector extraCodecs; + std::vector disabledCodecs; bool running; bool verbose; From e27c22d17d6712a0e6ecc24ebce42d4376a74dc1 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 14 Jul 2020 16:38:26 +0000 Subject: [PATCH 091/148] I2c_MultiTLVCodec: using smart pointers to simplify the code --- core/I2c_MultiTLVCodec.cpp | 47 +++++++++++-------------------------- include/I2c_MultiTLVCodec.h | 7 +++--- 2 files changed, 18 insertions(+), 36 deletions(-) diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 6127b5010..ee729c986 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -44,7 +44,7 @@ static I2c_Codec::CodecType getCodecTypeFromString(const std::string& str) } I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdmConfig, bool isVerbose) -: masterCodec(0), running(false), verbose(isVerbose) +: masterCodec(nullptr), running(false), verbose(isVerbose) { std::vector
addresses; std::vector tokens = split(cfgString, ';'); @@ -88,10 +88,9 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm I2c_Codec::CodecType type = addr.type; std::string required = addr.required; // Check for presence of TLV codec and take the first one we find as the master codec - I2c_Codec *testCodec = new I2c_Codec(i2cBus, address, type); + std::unique_ptr testCodec(new I2c_Codec(i2cBus, address, type)); testCodec->setMode(mode); if(testCodec->initCodec() != 0) { - delete testCodec; std::string err = "Codec requested but not found at: " + std::to_string(i2cBus) + ", " + std::to_string(address) + ", " + std::to_string(type) + "\n"; if("r" == required) throwErr(err); @@ -104,11 +103,11 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm fprintf(stderr, "Found I2C codec on bus %d address %d, required: %s\n", i2cBus, address, required.c_str()); } if("d" == required) - disabledCodecs.push_back(testCodec); + disabledCodecs.push_back(std::move(testCodec)); else if(!masterCodec) - masterCodec = testCodec; + masterCodec = std::move(testCodec); else - extraCodecs.push_back(testCodec); + extraCodecs.push_back(std::move(testCodec)); } } if(!masterCodec) { @@ -155,8 +154,7 @@ int I2c_MultiTLVCodec::initCodec() if(!masterCodec || (ret = masterCodec->initCodec())) return ret; - std::vector::iterator it; - for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { if((ret = (*it)->initCodec())) return ret; } @@ -172,8 +170,7 @@ int I2c_MultiTLVCodec::startAudio(int dual_rate) return ret; // Each subsequent codec occupies the next 2 slots - std::vector::iterator it; - for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { if((ret = (*it)->startAudio(0))) return ret; } @@ -191,8 +188,7 @@ int I2c_MultiTLVCodec::stopAudio() if(running) { // Stop extra codecs - std::vector::iterator it; - for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { (*it)->stopAudio(); } @@ -213,8 +209,7 @@ int I2c_MultiTLVCodec::setPga(float newGain, unsigned short int channel) if((ret = masterCodec->setPga(newGain, channel))) return ret; - std::vector::iterator it; - for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { if((ret = (*it)->setPga(newGain, channel))) return ret; } @@ -231,8 +226,7 @@ int I2c_MultiTLVCodec::setDACVolume(int halfDbSteps) if((ret = masterCodec->setDACVolume(halfDbSteps))) return ret; - std::vector::iterator it; - for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { if((ret = (*it)->setDACVolume(halfDbSteps))) return ret; } @@ -249,8 +243,7 @@ int I2c_MultiTLVCodec::setADCVolume(int halfDbSteps) if((ret = masterCodec->setADCVolume(halfDbSteps))) return ret; - std::vector::iterator it; - for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { if((ret = (*it)->setADCVolume(halfDbSteps))) return ret; } @@ -267,8 +260,7 @@ int I2c_MultiTLVCodec::setHPVolume(int halfDbSteps) if((ret = masterCodec->setHPVolume(halfDbSteps))) return ret; - std::vector::iterator it; - for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { if((ret = (*it)->setHPVolume(halfDbSteps))) return ret; } @@ -282,8 +274,7 @@ int I2c_MultiTLVCodec::disable() return 1; // Disable extra codecs first - std::vector::iterator it; - for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { (*it)->stopAudio(); } @@ -300,8 +291,7 @@ int I2c_MultiTLVCodec::reset() if((ret = masterCodec->reset())) return ret; - std::vector::iterator it; - for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { + for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { if((ret = (*it)->reset())) return ret; } @@ -339,15 +329,6 @@ int I2c_MultiTLVCodec::debugReadRegister(int codecNum, int regNum) { I2c_MultiTLVCodec::~I2c_MultiTLVCodec() { stopAudio(); - - // Delete codec objects we created - std::vector::iterator it; - for(it = extraCodecs.begin(); it != extraCodecs.end(); ++it) - delete *it; - if(masterCodec) - delete masterCodec; - for(it = disabledCodecs.begin(); it != disabledCodecs.end(); ++it) - delete *it; } McaspConfig& I2c_MultiTLVCodec::getMcaspConfig() diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index b62425cd3..9b6609984 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -13,6 +13,7 @@ #pragma once #include +#include #include "I2c_Codec.h" class I2c_MultiTLVCodec : public AudioCodec @@ -52,9 +53,9 @@ class I2c_MultiTLVCodec : public AudioCodec protected: McaspConfig mcaspConfig; private: - I2c_Codec *masterCodec; - std::vector extraCodecs; - std::vector disabledCodecs; + std::unique_ptr masterCodec; + std::vector> extraCodecs; + std::vector> disabledCodecs; bool running; bool verbose; From 51700d70a176803c1b1554da1eff92e1344a2412 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 14 Jul 2020 17:14:18 +0000 Subject: [PATCH 092/148] I2c_MultiTLVCodec: treating all the codecs the same except when needed, and simplified the code accordingly --- include/I2c_MultiTLVCodec.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index 9b6609984..5d7b92c4c 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -53,9 +53,9 @@ class I2c_MultiTLVCodec : public AudioCodec protected: McaspConfig mcaspConfig; private: - std::unique_ptr masterCodec; - std::vector> extraCodecs; - std::vector> disabledCodecs; + std::shared_ptr masterCodec; // this will be the same as one of the codecs + std::vector> codecs; + std::vector> disabledCodecs; bool running; bool verbose; From c743d8efe3ac985366ee6a009b747d44561c5201 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 14 Jul 2020 18:36:58 +0000 Subject: [PATCH 093/148] I2c_MultiTLVCodec: even simpler code --- core/I2c_MultiTLVCodec.cpp | 182 ++++++++++++------------------------- 1 file changed, 57 insertions(+), 125 deletions(-) diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index ee729c986..3c743e823 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -88,7 +88,7 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm I2c_Codec::CodecType type = addr.type; std::string required = addr.required; // Check for presence of TLV codec and take the first one we find as the master codec - std::unique_ptr testCodec(new I2c_Codec(i2cBus, address, type)); + std::shared_ptr testCodec(new I2c_Codec(i2cBus, address, type)); testCodec->setMode(mode); if(testCodec->initCodec() != 0) { std::string err = "Codec requested but not found at: " + std::to_string(i2cBus) + ", " + std::to_string(address) + ", " + std::to_string(type) + "\n"; @@ -103,16 +103,16 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm fprintf(stderr, "Found I2C codec on bus %d address %d, required: %s\n", i2cBus, address, required.c_str()); } if("d" == required) - disabledCodecs.push_back(std::move(testCodec)); - else if(!masterCodec) - masterCodec = std::move(testCodec); + disabledCodecs.push_back(testCodec); else - extraCodecs.push_back(std::move(testCodec)); + codecs.push_back(testCodec); } } - if(!masterCodec) { + if(!codecs.size()) { return; } + + masterCodec = codecs[0]; // Master codec generates bclk (and possibly wclk) with its PLL // and occupies the first two slots starting from tdmConfig.firstSlot unsigned int slotNum = tdmConfig.firstSlot; @@ -133,9 +133,12 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm params.generatesWclk = codecWclkMaster; params.mclk = masterCodec->getMcaspConfig().getValidAhclk(24000000); masterCodec->setParameters(params); + params.generatesBclk = false; params.generatesWclk = false; - for(auto& codec : extraCodecs) { + for(auto& codec : codecs) { + if(codec == masterCodec) + continue; slotNum += 2; params.startingSlot = slotNum; codec->setParameters(params); @@ -147,34 +150,41 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm mcaspConfig.params.outChannels = getNumOuts(); } +#define DO_AND_RETURN_ON_ERR(DO) \ + int ret; \ + if((ret = DO)) \ + return ret; \ +// end DO_AND_RETURN_ON_ERR + +#define FOR_EACH_CODEC_DO_MASTER(DO,MASTER_POS) \ + if(1 == MASTER_POS) { \ + DO_AND_RETURN_ON_ERR(masterCodec->DO); \ + } \ + for(auto& c : codecs) { \ + if(MASTER_POS && masterCodec == c) \ + continue; \ + DO_AND_RETURN_ON_ERR(c->DO); \ + } \ + if(2 == MASTER_POS) { \ + DO_AND_RETURN_ON_ERR(masterCodec->DO); \ + } \ +// end FOR_EACH_CODEC_DO_MASTER + +#define FOR_EACH_CODEC_DO_MASTER_FIRST(DO) FOR_EACH_CODEC_DO_MASTER(DO,1) +#define FOR_EACH_CODEC_DO_MASTER_LAST(DO) FOR_EACH_CODEC_DO_MASTER(DO,2) +#define FOR_EACH_CODEC_DO(DO) FOR_EACH_CODEC_DO_MASTER(DO,0) + // This method initialises the audio codec to its default state int I2c_MultiTLVCodec::initCodec() { - int ret = 1; - if(!masterCodec || (ret = masterCodec->initCodec())) - return ret; - - for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { - if((ret = (*it)->initCodec())) - return ret; - } - + FOR_EACH_CODEC_DO(initCodec()); return 0; } // Tell the codec to start generating audio int I2c_MultiTLVCodec::startAudio(int dual_rate) { - int ret = 1; - if(!masterCodec || (ret = masterCodec->startAudio(0))) - return ret; - - // Each subsequent codec occupies the next 2 slots - for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { - if((ret = (*it)->startAudio(0))) - return ret; - } - + FOR_EACH_CODEC_DO(startAudio(dual_rate)); running = true; return 0; } @@ -182,148 +192,64 @@ int I2c_MultiTLVCodec::startAudio(int dual_rate) int I2c_MultiTLVCodec::stopAudio() { - int ret = 0; - if(!masterCodec) - return 1; - if(running) { - // Stop extra codecs - for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { - (*it)->stopAudio(); - } - - // Stop master codec providing the clock; return value from this codec - ret = masterCodec->stopAudio(); + FOR_EACH_CODEC_DO_MASTER_LAST(stopAudio()); } running = false; - return ret; + return 0; } int I2c_MultiTLVCodec::setPga(float newGain, unsigned short int channel) { - int ret = 0; - if(!masterCodec) - return 1; - - if((ret = masterCodec->setPga(newGain, channel))) - return ret; - - for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { - if((ret = (*it)->setPga(newGain, channel))) - return ret; - } - + FOR_EACH_CODEC_DO(setPga(newGain, channel)); return 0; } int I2c_MultiTLVCodec::setDACVolume(int halfDbSteps) { - int ret = 0; - if(!masterCodec) - return 1; - - if((ret = masterCodec->setDACVolume(halfDbSteps))) - return ret; - - for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { - if((ret = (*it)->setDACVolume(halfDbSteps))) - return ret; - } - + FOR_EACH_CODEC_DO(setDACVolume(halfDbSteps)); return 0; } int I2c_MultiTLVCodec::setADCVolume(int halfDbSteps) { - int ret = 0; - if(!masterCodec) - return 1; - - if((ret = masterCodec->setADCVolume(halfDbSteps))) - return ret; - - for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { - if((ret = (*it)->setADCVolume(halfDbSteps))) - return ret; - } - + FOR_EACH_CODEC_DO(setADCVolume(halfDbSteps)); return 0; } int I2c_MultiTLVCodec::setHPVolume(int halfDbSteps) { - int ret = 0; - if(!masterCodec) - return 1; - - if((ret = masterCodec->setHPVolume(halfDbSteps))) - return ret; - - for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { - if((ret = (*it)->setHPVolume(halfDbSteps))) - return ret; - } - + FOR_EACH_CODEC_DO(setHPVolume(halfDbSteps)); return 0; } int I2c_MultiTLVCodec::disable() { - if(!masterCodec) - return 1; - // Disable extra codecs first - for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { - (*it)->stopAudio(); - } - - // Disable master codec providing the clock; return value from this codec - return masterCodec->stopAudio(); + FOR_EACH_CODEC_DO_MASTER_LAST(stopAudio()); + return 0; } int I2c_MultiTLVCodec::reset() { - int ret = 0; - if(!masterCodec) - return 1; - - if((ret = masterCodec->reset())) - return ret; - - for(auto it = extraCodecs.begin(); it != extraCodecs.end(); ++it) { - if((ret = (*it)->reset())) - return ret; - } - + FOR_EACH_CODEC_DO(reset()); return 0; } -// How many I2C codecs were found? (range 0-4) +// How many I2C codecs were found? int I2c_MultiTLVCodec::numDetectedCodecs() { - if(!masterCodec) - return 0; - return extraCodecs.size() + 1; + return codecs.size(); } // For debugging purposes only! void I2c_MultiTLVCodec::debugWriteRegister(int codecNum, int regNum, int value) { - if(codecNum == 0) { - masterCodec->writeRegister(regNum, value); - } - else { - extraCodecs[codecNum - 1]->writeRegister(regNum, value); - } + codecs.at(codecNum)->writeRegister(regNum, value); } int I2c_MultiTLVCodec::debugReadRegister(int codecNum, int regNum) { - if(codecNum == 0) { - return masterCodec->readRegister(regNum); - } - else { - return extraCodecs[codecNum - 1]->readRegister(regNum); - } + return codecs.at(codecNum)->readRegister(regNum); } I2c_MultiTLVCodec::~I2c_MultiTLVCodec() @@ -353,11 +279,17 @@ McaspConfig& I2c_MultiTLVCodec::getMcaspConfig() } unsigned int I2c_MultiTLVCodec::getNumIns(){ - return 2 * numDetectedCodecs(); + unsigned int sum = 0; + for(auto& c : codecs) + sum += c->getNumIns(); + return sum; } unsigned int I2c_MultiTLVCodec::getNumOuts(){ - return 2 * numDetectedCodecs(); + unsigned int sum = 0; + for(auto& c : codecs) + sum += c->getNumOuts(); + return sum; } float I2c_MultiTLVCodec::getSampleRate() { From 35c00f1a3e42879b7a0265ca5a2dd0214b8a4e4a Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 14 Jul 2020 18:44:32 +0000 Subject: [PATCH 094/148] I2cMultiTLVCodec: _really_ treating all the codecs the same --- core/I2c_MultiTLVCodec.cpp | 63 +++++++++++++++++++------------------ include/I2c_MultiTLVCodec.h | 2 +- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 3c743e823..68f26ad84 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -15,7 +15,7 @@ using namespace StringUtils; static const unsigned int kDataSize = 16; -#undef CODEC_WCLK_MASTER +#undef CODEC_GENERATES_WCLK struct Address { unsigned int bus; @@ -44,7 +44,7 @@ static I2c_Codec::CodecType getCodecTypeFromString(const std::string& str) } I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdmConfig, bool isVerbose) -: masterCodec(nullptr), running(false), verbose(isVerbose) +: primaryCodec(nullptr), running(false), verbose(isVerbose) { std::vector
addresses; std::vector tokens = split(cfgString, ';'); @@ -87,7 +87,8 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm uint8_t address = addr.address; I2c_Codec::CodecType type = addr.type; std::string required = addr.required; - // Check for presence of TLV codec and take the first one we find as the master codec + // Check for presence of TLV codecs and take the first one we + // find as the primary codec std::shared_ptr testCodec(new I2c_Codec(i2cBus, address, type)); testCodec->setMode(mode); if(testCodec->initCodec() != 0) { @@ -112,15 +113,15 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm return; } - masterCodec = codecs[0]; - // Master codec generates bclk (and possibly wclk) with its PLL + primaryCodec = codecs[0]; + // primaryCodec generates bclk (and possibly wclk) with its PLL // and occupies the first two slots starting from tdmConfig.firstSlot unsigned int slotNum = tdmConfig.firstSlot; - bool codecWclkMaster = -#ifdef CODEC_WCLK_MASTER - true; // Main codec generates word clock + bool primaryCodecGeneratesWclk = +#ifdef CODEC_GENERATES_WCLK + true; // primaryCodec generates word clock #else - false; // AM335x generates word clock + false; // AM335x or external device generates word clock #endif AudioCodecParams params; @@ -130,21 +131,21 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm params.tdmMode = true; params.startingSlot = slotNum; params.generatesBclk = true; - params.generatesWclk = codecWclkMaster; - params.mclk = masterCodec->getMcaspConfig().getValidAhclk(24000000); - masterCodec->setParameters(params); + params.generatesWclk = primaryCodecGeneratesWclk; + params.mclk = primaryCodec->getMcaspConfig().getValidAhclk(24000000); + primaryCodec->setParameters(params); params.generatesBclk = false; params.generatesWclk = false; for(auto& codec : codecs) { - if(codec == masterCodec) + if(codec == primaryCodec) continue; slotNum += 2; params.startingSlot = slotNum; codec->setParameters(params); } // initialise the McASP configuration. - mcaspConfig = masterCodec->getMcaspConfig(); + mcaspConfig = primaryCodec->getMcaspConfig(); mcaspConfig.params.dataSize = kDataSize; mcaspConfig.params.inChannels = getNumIns(); mcaspConfig.params.outChannels = getNumOuts(); @@ -156,23 +157,23 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm return ret; \ // end DO_AND_RETURN_ON_ERR -#define FOR_EACH_CODEC_DO_MASTER(DO,MASTER_POS) \ - if(1 == MASTER_POS) { \ - DO_AND_RETURN_ON_ERR(masterCodec->DO); \ +#define FOR_EACH_CODEC_DO_PRIMARY(DO,PRIMARY_POS) \ + if(1 == PRIMARY_POS) { \ + DO_AND_RETURN_ON_ERR(primaryCodec->DO); \ } \ for(auto& c : codecs) { \ - if(MASTER_POS && masterCodec == c) \ + if(PRIMARY_POS && primaryCodec == c) \ continue; \ DO_AND_RETURN_ON_ERR(c->DO); \ } \ - if(2 == MASTER_POS) { \ - DO_AND_RETURN_ON_ERR(masterCodec->DO); \ + if(2 == PRIMARY_POS) { \ + DO_AND_RETURN_ON_ERR(primaryCodec->DO); \ } \ -// end FOR_EACH_CODEC_DO_MASTER +// end FOR_EACH_CODEC_DO_PRIMARY -#define FOR_EACH_CODEC_DO_MASTER_FIRST(DO) FOR_EACH_CODEC_DO_MASTER(DO,1) -#define FOR_EACH_CODEC_DO_MASTER_LAST(DO) FOR_EACH_CODEC_DO_MASTER(DO,2) -#define FOR_EACH_CODEC_DO(DO) FOR_EACH_CODEC_DO_MASTER(DO,0) +#define FOR_EACH_CODEC_DO_PRIMARY_FIRST(DO) FOR_EACH_CODEC_DO_PRIMARY(DO,1) +#define FOR_EACH_CODEC_DO_PRIMARY_LAST(DO) FOR_EACH_CODEC_DO_PRIMARY(DO,2) +#define FOR_EACH_CODEC_DO(DO) FOR_EACH_CODEC_DO_PRIMARY(DO,0) // This method initialises the audio codec to its default state int I2c_MultiTLVCodec::initCodec() @@ -193,7 +194,7 @@ int I2c_MultiTLVCodec::startAudio(int dual_rate) int I2c_MultiTLVCodec::stopAudio() { if(running) { - FOR_EACH_CODEC_DO_MASTER_LAST(stopAudio()); + FOR_EACH_CODEC_DO_PRIMARY_LAST(stopAudio()); } running = false; @@ -227,7 +228,7 @@ int I2c_MultiTLVCodec::setHPVolume(int halfDbSteps) int I2c_MultiTLVCodec::disable() { // Disable extra codecs first - FOR_EACH_CODEC_DO_MASTER_LAST(stopAudio()); + FOR_EACH_CODEC_DO_PRIMARY_LAST(stopAudio()); return 0; } @@ -266,15 +267,15 @@ McaspConfig& I2c_MultiTLVCodec::getMcaspConfig() #define BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE 0x00 // External clk, polarity (falling edge) #define BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits #define BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE 0x00 // External clk, polarity (falling edge) -#ifdef CODEC_WCLK_MASTER +#ifdef CODEC_GENERATES_WCLK #define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x800 // 16-slot TDM external fsclk, rising edge means beginning of frame #define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x800 // 16-slot TDM external fsclk, rising edge means beginning of frame #define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 2) // AHCLKX and AXR2 outputs -#else // CODEC_WCLK_MASTER +#else // CODEC_GENERATES_WCLK #define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x802 // 16-slot TDM internal fsclk, rising edge means beginning of frame #define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x802 // 16-slot TDM internal fsclk, rising edge means beginning of frame #define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | MCASP_PIN_AFSX | (1 << 2) // AHCLKX, FSX, AXR2 outputs -#endif // CODEC_WCLK_MASTER +#endif // CODEC_GENERATES_WCLK */ } @@ -293,7 +294,7 @@ unsigned int I2c_MultiTLVCodec::getNumOuts(){ } float I2c_MultiTLVCodec::getSampleRate() { - if(masterCodec) - return masterCodec->getSampleRate(); + if(primaryCodec) + return primaryCodec->getSampleRate(); return 0; } diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index 5d7b92c4c..7c5208556 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -53,7 +53,7 @@ class I2c_MultiTLVCodec : public AudioCodec protected: McaspConfig mcaspConfig; private: - std::shared_ptr masterCodec; // this will be the same as one of the codecs + std::shared_ptr primaryCodec; // this will be the same as one of the elements of codecs std::vector> codecs; std::vector> disabledCodecs; From 5cffec00462a7cddd1af43ab55cb40630515f48c Mon Sep 17 00:00:00 2001 From: Andrew McPherson Date: Sun, 5 Jul 2020 23:08:36 +0100 Subject: [PATCH 095/148] I2c_Codec: updates for string preamp board: adjustable sampling rate and MICBIAS set to 2.0V --- core/I2c_Codec.cpp | 40 +++++++++++++++++++++++++------------- core/I2c_MultiTLVCodec.cpp | 1 + include/AudioCodec.h | 1 + 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index ea4dd3033..c59848764 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -32,6 +32,7 @@ I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, CodecType type, bool isVerbose params.generatesBclk = true; params.generatesWclk = true; params.mclk = mcaspConfig.getValidAhclk(24000000); + params.samplingRate = 44100; initI2C_RW(i2cBus, i2cAddress, -1); } @@ -88,7 +89,7 @@ int I2c_Codec::startAudio(int dummy) return 1; if(params.generatesBclk) { - if(setAudioSamplingRate(44100)) + if(setAudioSamplingRate(params.samplingRate)) return 1; } else { @@ -180,17 +181,33 @@ int I2c_Codec::startAudio(int dummy) } } // if not noInit - //Set-up hardware high-pass filter for DC removal + bool dcRemoval; + double micBias; if(codecType == TLV320AIC3104) { - if(configureDCRemovalIIR(true)) - return 1; + //Set-up hardware high-pass filter for DC removal + dcRemoval = true; + micBias = 2.5; } else { // Disable DC blocking for differential analog inputs - if(configureDCRemovalIIR(false)) - return 1; + dcRemoval = false; + // mini string preamp uses micBias for virtual ground reference + micBias = 2; } - if(writeRegister(25, 0b10000000)) // Enable mic bias 2.5V + + if(configureDCRemovalIIR(dcRemoval)) + return 1; + uint8_t micBiasField; + if(2.5 < micBias) + micBiasField = 0b11; // MICBIAS is connected to AVDD + else if (2 < micBias) + micBiasField = 0b10; // MICBIAS is powered to 2.5V + else if (micBias == 2) + micBiasField = 0b01; // MICBIAS is powered to 2V + else + micBiasField = 0b00; // MICBIAS is powered down + + if(writeRegister(0x19, micBiasField << 6)) // Set MICBIAS return 1; // TODO: may need to separate the code below for non-master codecs so they enable amps after the master clock starts @@ -835,10 +852,7 @@ unsigned int I2c_Codec::getNumOuts(){ } float I2c_Codec::getSampleRate() { - if(params.dualRate) - return 88200; - else - return 44100; + return params.samplingRate; } int I2c_Codec::setParameters(const AudioCodecParams& codecParams) @@ -849,8 +863,8 @@ int I2c_Codec::setParameters(const AudioCodecParams& codecParams) verbose && fprintf(stderr, "I2c_Codec: cannot generate Wclk if it doesn't generate Bclk\n"); ret = -1; } - if(params.dualRate) { - verbose && fprintf(stderr, "I2c_Codec: dualRate is not tested\n"); + if(params.samplingRate > 53000 || params.samplingRate < 39000) { + verbose && fprintf(stderr, "I2c_Codec: sample rate %f out of range\n", params.samplingRate); ret = -1; } if(params.bitDelay > 2) { diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 68f26ad84..0d6cb8272 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -133,6 +133,7 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm params.generatesBclk = true; params.generatesWclk = primaryCodecGeneratesWclk; params.mclk = primaryCodec->getMcaspConfig().getValidAhclk(24000000); + params.samplingRate = 44100; primaryCodec->setParameters(params); params.generatesBclk = false; diff --git a/include/AudioCodec.h b/include/AudioCodec.h index a454191ce..e5c804302 100644 --- a/include/AudioCodec.h +++ b/include/AudioCodec.h @@ -8,6 +8,7 @@ struct AudioCodecParams { unsigned int startingSlot; // what slot in the TDM frame to place the first channel in unsigned int bitDelay; // additional offset in the TDM frame (in bits) double mclk; // frequency of the master clock passed to the codec + double samplingRate; // audio sampling rate bool dualRate; // whether to run at single or double sampling rate bool tdmMode; // whether to use TDM rather than DSP mode bool generatesBclk; // whether the codec generates the bit clock From 91b1d6d4941b80f7db63ab7b708e942004c5c257 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 21 Jul 2020 19:38:50 +0100 Subject: [PATCH 096/148] board_detect: suppress misleading error --- core/board_detect.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/board_detect.cpp b/core/board_detect.cpp index 0189909ba..a89c510e4 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -112,7 +112,8 @@ static BelaHw read_hw_from_file(const std::string& path, const std::string& sear if(hw != BelaHw_NoHw) return hw; else - fprintf(stderr, "Unknown setting %s= in %s: %s. Ignoring.\n", searchStr.c_str(), path.c_str(), board.c_str()); + if("" != board) + fprintf(stderr, "Unknown setting %s= in %s: %s. Ignoring.\n", searchStr.c_str(), path.c_str(), board.c_str()); return BelaHw_NoHw; } From 1ec5e9eea38e26f083b99e7989bf1535de1cf509 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 17 Aug 2020 17:06:01 +0000 Subject: [PATCH 097/148] RTAudio: (roughly) fixed fifoFactor for new BelaHws --- core/RTAudio.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 3b8f6e58f..9bc232882 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -468,23 +468,17 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) switch(belaHw) { case BelaHw_Bela: - //nobreak case BelaHw_BelaMini: - //nobreak case BelaHw_Salt: fifoFactor = settings->periodSize / 128; break; - case BelaHw_BelaMiniMultiTdm: - case BelaHw_BelaMiniMultiAudio: - //TODO: we are assuming 6 in / 6 out - //nobreak case BelaHw_CtagFace: - //nobreak case BelaHw_CtagFaceBela: fifoFactor = settings->periodSize / 64; break; case BelaHw_CtagBeast: - //nobreak + case BelaHw_BelaMiniMultiTdm: + case BelaHw_BelaMiniMultiAudio: case BelaHw_CtagBeastBela: fifoFactor = settings->periodSize / 32; break; From 7e25ef1e5cbb45ac8e3c8f430b3369bc974a24f2 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Sat, 22 Aug 2020 11:36:10 +0000 Subject: [PATCH 098/148] Batch: crude implementation to allow offline batch processing --- core/RTAudio.cpp | 60 ++++++++++++++++++++++++++++++++++++++++--- core/board_detect.cpp | 3 +++ include/Bela.h | 20 ++++++++++----- 3 files changed, 73 insertions(+), 10 deletions(-) diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 9bc232882..9d2bb54d7 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -126,6 +126,7 @@ typedef struct int gRTAudioVerbose = 0; // Verbosity level for debugging AudioCodec* gAudioCodec = NULL; static AudioCodec* gDisabledCodec = NULL; +static BelaHw belaHw; static int Bela_getHwConfigPrivate(BelaHw hw, BelaHwConfig* cfg, BelaHwConfigPrivate* pcfg) { @@ -226,6 +227,44 @@ void fifoRender(BelaContext*, void*); // // Returns 0 on success. +int initBatch(BelaInitSettings *settings, InternalBelaContext* ctx, const std::string& codecMode, void* userData) +{ + ctx->audioFrames = settings->periodSize; + ctx->audioInChannels = 12; + ctx->audioOutChannels = 12; + ctx->digitalChannels = 16; + ctx->analogInChannels = settings->numAnalogInChannels; + ctx->analogOutChannels = settings->numAnalogOutChannels; + ctx->analogFrames = ctx->audioFrames / 2; + ctx->digitalFrames = ctx->audioFrames; + ctx->audioSampleRate = 44100; + ctx->digitalSampleRate = ctx->audioSampleRate; + ctx->analogSampleRate = ctx->audioSampleRate / 2; + BelaContextSplitter::contextAllocate(ctx); + ctx->flags |= BELA_FLAG_OFFLINE; + // Call the user-defined initialisation function + if(settings->setup && !(*settings->setup)((BelaContext*)ctx, userData)) { + if(gRTAudioVerbose) + fprintf(stderr, "Couldn't initialise audio rendering: setup() returned false\n"); + return 1; + } + + return 0; +} + +static int batchCallbackLoop(InternalBelaContext* context, void (*render)(BelaContext*,void*), void* userData) +{ + context->audioFramesElapsed = 0; + unsigned int i = 100000; + while(i--) { + render((BelaContext*)context, userData); + context->audioFramesElapsed += context->audioFrames; + } + gShouldStop = 1; + return 0; +} + + int Bela_initAudio(BelaInitSettings *settings, void *userData) { if(!settings) @@ -394,7 +433,6 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) if(gRTAudioVerbose) printf("Hardware specified in the user's belaconfig: %s\n", getBelaHwName(userHw).c_str()); } - BelaHw belaHw; if(userHw == actualHw) belaHw = userHw; else if(userHw != BelaHw_NoHw && Bela_checkHwCompatibility(userHw, actualHw)) @@ -413,6 +451,11 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) if(settings->codecMode) codecMode = settings->codecMode; + if(BelaHw_Batch == belaHw) + { + gCoreRender = settings->render; + return initBatch(settings, &gContext, codecMode, gUserData); + } // figure out which codec to use and which to disable if several are present and conflicting unsigned int ctags; if((ctags = Bela_hwContains(belaHw, CtagCape))) @@ -483,6 +526,7 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) fifoFactor = settings->periodSize / 32; break; case BelaHw_NoHw: + case BelaHw_Batch: break; } if(1 > fifoFactor) @@ -684,6 +728,10 @@ void fifoLoop(void* userData) static int startAudioInline(){ if(gRTAudioVerbose) printf("startAudioInilne\n"); + gShouldStop = 0; + if(BelaHw_Batch == belaHw) { + return 0; + } // make sure we have everything assert(gAudioCodec != 0 && gPRU != 0); @@ -708,7 +756,6 @@ static int startAudioInline(){ } // ready to go - gShouldStop = 0; return 0; } @@ -774,6 +821,10 @@ int Bela_startAudio() if(ret < 0) return ret; + if(BelaHw_Batch == belaHw) { + return batchCallbackLoop(&gContext, gCoreRender, gUserData); + } + // Start all RT threads #ifdef XENOMAI_SKIN_native if(ret = rt_task_start(&gRTAudioThread, &audioLoop, 0)) @@ -824,6 +875,8 @@ void Bela_stopAudio() printf("Stopping audio...\n"); // Tell audio thread to stop (if this hasn't been done already) Bela_requestStop(); + if(BelaHw_Batch == belaHw) + return; // Now wait for threads to respond and actually stop... #ifdef XENOMAI_SKIN_native @@ -857,7 +910,8 @@ void Bela_cleanupAudio() disable_runfast(); // Shut down the prussdrv system - gPRU->exitPRUSS(); + if(gPRU) + gPRU->exitPRUSS(); // Clean up the auxiliary tasks Bela_deleteAllAuxiliaryTasks(); diff --git a/core/board_detect.cpp b/core/board_detect.cpp index a89c510e4..9d0a8ff6a 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -21,6 +21,7 @@ static const std::map belaHwMap = { {"CtagBeastBela", BelaHw_CtagBeastBela}, {"BelaMiniMultiAudio", BelaHw_BelaMiniMultiAudio}, {"BelaMiniMultiTdm", BelaHw_BelaMiniMultiTdm}, + {"Batch", BelaHw_Batch}, }; static const int EEPROM_NUMCHARS = 30; @@ -193,6 +194,8 @@ using namespace BelaHwComponent; /// can I run userHw when I actually have detectedHw? bool Bela_checkHwCompatibility(BelaHw userHw, BelaHw detectedHw) { + if(BelaHw_Batch == userHw) + return true; if(userHw == BelaHw_Bela && Bela_hwContains(detectedHw, BelaCape)) return true; else if(userHw == BelaHw_CtagFace && Bela_hwContains(detectedHw, CtagCape)) diff --git a/include/Bela.h b/include/Bela.h index 672842644..d4dbbd5f2 100644 --- a/include/Bela.h +++ b/include/Bela.h @@ -95,6 +95,7 @@ typedef enum BelaHw_CtagBeastBela, ///< Ctag Beast and Bela cape BelaHw_BelaMiniMultiAudio, ///< Bela Mini with extra codecs BelaHw_BelaMiniMultiTdm, ///< Bela Mini with extra codes and tdm devices + BelaHw_Batch, ///< Dummy offline } BelaHw; typedef struct _BelaHwConfig @@ -193,6 +194,10 @@ typedef enum * Flag for BelaContext. If set, indicates the user will be warned if an underrun occurs */ #define BELA_FLAG_DETECT_UNDERRUNS (1 << 2) // Set if the user will be displayed a message when an underrun occurs +/** + * Flag for BelaContext. If set, it means that render() is called offline, i.e.: the audio time does not correspond to wall clock time. + */ +#define BELA_FLAG_OFFLINE (1 << 3) struct option; @@ -383,10 +388,10 @@ typedef struct { /// /// Binary combination of flags including: /// - /// BELA_FLAG_INTERLEAVED: indicates the audio and analog buffers are interleaved - /// - /// BELA_FLAG_ANALOG_OUTPUTS_PERSIST: indicates that writes to the analog outputs will - /// persist for future frames. If not set, writes affect one frame only. + /// BELA_FLAG_INTERLEAVED + /// BELA_FLAG_ANALOG_OUTPUTS_PERSIST + /// BELA_FLAG_DETECT_UNDERRUNS + /// BELA_FLAG_OFFLINE const uint32_t flags; /// Name of running project. @@ -408,10 +413,11 @@ typedef struct { typedef struct { // These items might be adjusted by the user: - /// \brief Number of (analog) frames per period. + /// \brief Number of audio frames per period ("blocksize"). /// - /// Number of audio frames depends on relative sample rates of the two. By default, - /// audio is twice the sample rate, so has twice the period size. + /// The number of analog frames depends on relative sample rates of the + /// two. By default, audio is twice the sample rate, so has twice the + /// period size. int periodSize; /// Whether to use the analog input and output int useAnalog; From 17216b3f7f4ec217a04c0f7fcb7cef089fbc6e60 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 22 Jan 2021 15:58:55 +0000 Subject: [PATCH 099/148] PRU: BOARD_FLAGS_BELA_MINI only should indicate whether DAC is there, what CS to use for ADC and the DIGITAL mapping. BOARD_FLAGS_BELA_GENERIC_TDM has other applicatons --- core/PRU.cpp | 6 +++--- pru/pru_rtaudio_irq.p | 6 ------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/core/PRU.cpp b/core/PRU.cpp index bc38a15db..99a6eda21 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -561,9 +561,6 @@ void PRU::initialisePruCommon(const McaspRegisters& mcaspRegisters) { uint32_t board_flags = 0; switch(belaHw) { - case BelaHw_BelaMini: - board_flags |= 1 << BOARD_FLAGS_BELA_MINI; - break; case BelaHw_BelaMiniMultiTdm: case BelaHw_BelaMiniMultiAudio: board_flags |= 1 << BOARD_FLAGS_BELA_GENERIC_TDM; @@ -577,11 +574,14 @@ void PRU::initialisePruCommon(const McaspRegisters& mcaspRegisters) board_flags |= 1 << BOARD_FLAGS_CTAG_BEAST; break; case BelaHw_Bela: + case BelaHw_BelaMini: case BelaHw_Salt: case BelaHw_NoHw: default: break; } + if(Bela_hwContains(belaHw, BelaMiniCape)) + board_flags |= 1 << BOARD_FLAGS_BELA_MINI; pru_buffer_comm[PRU_COMM_BOARD_FLAGS] = board_flags; /* Set up flags */ pru_buffer_comm[PRU_COMM_SHOULD_STOP] = 0; diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index a4539130d..187050d23 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -422,7 +422,6 @@ DONE: .macro IF_HAS_ANALOG_DAC_JMP_TO .mparam DEST QBBS DONE, reg_flags, FLAG_BIT_BELA_MINI - QBBS DONE, reg_flags, FLAG_BIT_BELA_MULTI_TLV QBA DEST DONE: .endm @@ -616,7 +615,6 @@ DIGITAL: //r2 is gpio1_oe, r8 is gpio1_setdataout, r7 is gpio1_cleardataout, r27 is the input word //the following operations will read from r27 and update r2,r7,r8 QBBS BELA_SET_GPIO_BITS_0_MINI, reg_flags, FLAG_BIT_BELA_MINI -QBBS BELA_SET_GPIO_BITS_0_MINI, reg_flags, FLAG_BIT_BELA_MULTI_TLV QBA BELA_SET_GPIO_BITS_0_NOT_MINI BELA_SET_GPIO_BITS_0_MINI: SET_GPIO_BITS r2, r8, r7, 18, 0, r27 @@ -663,7 +661,6 @@ SET_GPIO_BITS_0_DONE: //r3 is gpio2_oe, r5 is gpio2_setdataout, r4 is gpio2_cleardataout, r27 is the input word //the following operations will read from r27 and update r3,r4,r5 QBBS BELA_SET_GPIO_BITS_1_MINI, reg_flags, FLAG_BIT_BELA_MINI -QBBS BELA_SET_GPIO_BITS_1_MINI, reg_flags, FLAG_BIT_BELA_MULTI_TLV QBA BELA_SET_GPIO_BITS_1_NOT_MINI BELA_SET_GPIO_BITS_1_MINI: SET_GPIO_BITS r3, r5, r4, 0, 7, r27 @@ -705,7 +702,6 @@ START_INTERMEDIATE_DONE: //now read from r2 and r3 only the channels that are set as input in the lower word of r27 // and set their value in the high word of r27 QBBS BELA_READ_GPIO_BITS_MINI, reg_flags, FLAG_BIT_BELA_MINI -QBBS BELA_READ_GPIO_BITS_MINI, reg_flags, FLAG_BIT_BELA_MULTI_TLV QBA BELA_READ_GPIO_BITS_NOT_MINI BELA_READ_GPIO_BITS_MINI: //GPIO1 @@ -808,13 +804,11 @@ QBA DALOOP .macro DAC_WRITE .mparam reg QBBS SKIP_DAC_WRITE_1, reg_flags, FLAG_BIT_BELA_MINI - QBBS SKIP_DAC_WRITE_1, reg_flags, FLAG_BIT_BELA_MULTI_TLV DAC_CS_ASSERT SKIP_DAC_WRITE_1: DAC_TX reg DAC_WAIT_FOR_FINISH QBBS SKIP_DAC_WRITE_2, reg_flags, FLAG_BIT_BELA_MINI - QBBS SKIP_DAC_WRITE_2, reg_flags, FLAG_BIT_BELA_MULTI_TLV DAC_CS_UNASSERT SKIP_DAC_WRITE_2: DAC_DISCARD_RX From 73c5e3afd383c34e7cfe5e1f20024fd66851dffb Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 22 Jan 2021 15:59:52 +0000 Subject: [PATCH 100/148] BelaMultiTdm: added new BelaHw and compatibilities --- core/PRU.cpp | 3 +++ core/RTAudio.cpp | 5 +++-- core/board_detect.cpp | 4 ++++ include/Bela.h | 3 ++- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/core/PRU.cpp b/core/PRU.cpp index 99a6eda21..b4f3f1edb 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -563,6 +563,7 @@ void PRU::initialisePruCommon(const McaspRegisters& mcaspRegisters) switch(belaHw) { case BelaHw_BelaMiniMultiTdm: case BelaHw_BelaMiniMultiAudio: + case BelaHw_BelaMultiTdm: board_flags |= 1 << BOARD_FLAGS_BELA_GENERIC_TDM; break; case BelaHw_CtagFace: @@ -666,6 +667,8 @@ int PRU::start(char * const filename, const McaspRegisters& mcaspRegisters) //nobreak case BelaHw_BelaMiniMultiTdm: //nobreak + case BelaHw_BelaMultiTdm: + //nobreak case BelaHw_CtagFace: //nobreak case BelaHw_CtagBeast: diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 9d2bb54d7..a700b75ef 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -473,8 +473,8 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) mode = "MODE:"+codecMode; gAudioCodec = new I2c_MultiTLVCodec("ADDR:2,24,3104,n;ADDR:2,25,3106,n;ADDR:2,26,3106,n;ADDR:2,27,3106,n;"+mode, {}, gRTAudioVerbose); } - else if(belaHw == BelaHw_BelaMiniMultiTdm) - gAudioCodec = new I2c_MultiTdmCodec(codecMode, gRTAudioVerbose); + else if(BelaHw_BelaMiniMultiTdm == belaHw || BelaHw_BelaMultiTdm == belaHw) + gAudioCodec = new I2c_MultiTdmCodec(codecMode != "" ? codecMode : "ADDR:2,24,3104,r", gRTAudioVerbose); else if(Bela_hwContains(belaHw, Tlv320aic3104)) { gAudioCodec = new I2c_Codec(codecI2cBus, codecI2cAddress, I2c_Codec::TLV320AIC3104, gRTAudioVerbose); @@ -520,6 +520,7 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) fifoFactor = settings->periodSize / 64; break; case BelaHw_CtagBeast: + case BelaHw_BelaMultiTdm: case BelaHw_BelaMiniMultiTdm: case BelaHw_BelaMiniMultiAudio: case BelaHw_CtagBeastBela: diff --git a/core/board_detect.cpp b/core/board_detect.cpp index 9d0a8ff6a..a035e6e2b 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -21,6 +21,7 @@ static const std::map belaHwMap = { {"CtagBeastBela", BelaHw_CtagBeastBela}, {"BelaMiniMultiAudio", BelaHw_BelaMiniMultiAudio}, {"BelaMiniMultiTdm", BelaHw_BelaMiniMultiTdm}, + {"BelaMultiTdm", BelaHw_BelaMultiTdm}, {"Batch", BelaHw_Batch}, }; @@ -204,6 +205,8 @@ bool Bela_checkHwCompatibility(BelaHw userHw, BelaHw detectedHw) return true; else if(userHw == BelaHw_Salt && Bela_hwContains(detectedHw, BelaCape)) return true; + else if (userHw == BelaHw_BelaMultiTdm && Bela_hwContains(detectedHw, BelaCape)) + return true; else if (userHw == BelaHw_BelaMini && Bela_hwContains(detectedHw, BelaMiniCape)) return true; else if (userHw == BelaHw_BelaMiniMultiAudio && Bela_hwContains(detectedHw, BelaMiniCape)) @@ -222,6 +225,7 @@ unsigned int Bela_hwContains(const BelaHw hw, const BelaHwComponent::Component c case BelaHw_Salt: case BelaHw_CtagFaceBela: case BelaHw_CtagBeastBela: + case BelaHw_BelaMultiTdm: return 1; default: return 0; diff --git a/include/Bela.h b/include/Bela.h index d4dbbd5f2..c62779757 100644 --- a/include/Bela.h +++ b/include/Bela.h @@ -94,7 +94,8 @@ typedef enum BelaHw_CtagFaceBela, ///< Ctag Face and Bela cape BelaHw_CtagBeastBela, ///< Ctag Beast and Bela cape BelaHw_BelaMiniMultiAudio, ///< Bela Mini with extra codecs - BelaHw_BelaMiniMultiTdm, ///< Bela Mini with extra codes and tdm devices + BelaHw_BelaMiniMultiTdm, ///< Bela Mini with extra codecs and/or tdm devices + BelaHw_BelaMultiTdm, ///< Bela with extra codecs and/or tdm devices BelaHw_Batch, ///< Dummy offline } BelaHw; From 0e8c1c6e47435afd355f23dbc6e14e6e69ddd1a9 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 2 Apr 2021 15:30:49 +0000 Subject: [PATCH 101/148] RTAudio: print mcasp registers when verbose --- core/RTAudio.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index a700b75ef..1d9bda0d0 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -742,8 +742,11 @@ static int startAudioInline(){ return -1; } + McaspConfig mcaspConfig = gAudioCodec->getMcaspConfig(); + if(gRTAudioVerbose) + mcaspConfig.print(); // initialize and run the PRU - if(gPRU->start(gPRUFilename, gAudioCodec->getMcaspConfig().getRegisters())) { + if(gPRU->start(gPRUFilename, mcaspConfig.getRegisters())) { fprintf(stderr, "Error: unable to start PRU from %s\n", gPRUFilename[0] ? "embedded binary" : gPRUFilename); return -1; } From 0af12aa8a4e29e8ce9e51d149442d9402d826fb4 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 2 Apr 2021 15:32:10 +0000 Subject: [PATCH 102/148] I2c_MultiTLVCodec: pass verbosity to codecs --- core/I2c_MultiTLVCodec.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 0d6cb8272..0ef0938c0 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -89,7 +89,7 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm std::string required = addr.required; // Check for presence of TLV codecs and take the first one we // find as the primary codec - std::shared_ptr testCodec(new I2c_Codec(i2cBus, address, type)); + std::shared_ptr testCodec(new I2c_Codec(i2cBus, address, type, isVerbose)); testCodec->setMode(mode); if(testCodec->initCodec() != 0) { std::string err = "Codec requested but not found at: " + std::to_string(i2cBus) + ", " + std::to_string(address) + ", " + std::to_string(type) + "\n"; From aec67c352de98790b7efdeb18a2b592c7fc2213e Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 2 Apr 2021 15:34:44 +0000 Subject: [PATCH 103/148] Mcasp: fixed printing --- core/Mcasp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/Mcasp.cpp b/core/Mcasp.cpp index c558ac870..16da04fe5 100644 --- a/core/Mcasp.cpp +++ b/core/Mcasp.cpp @@ -441,7 +441,7 @@ std::ostream& operator<< (std::ostream& out, const std::vector& v) { void McaspConfig::print() { #define P(FIELD) std::cout << #FIELD << ": " << params.FIELD << "\n" - std::cout << "Parameters:\n"; + std::cout << "Mcasp parameters:\n"; P(inChannels); P(outChannels); P(inSerializers); @@ -460,7 +460,7 @@ void McaspConfig::print() getRegisters(); // update the registers with the current parameters #define R(FIELD) printf("%10s: 0x%08x\n", #FIELD, regs.FIELD) - printf("Registers:\n"); + std::cout << "Mcasp registers:\n"; R(pdir); R(rmask); R(rfmt); From f495629e6017e8b85a9f6063f22588fbb041f8e5 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 2 Apr 2021 15:36:04 +0000 Subject: [PATCH 104/148] AudioCodec: :print() --- core/I2c_Codec.cpp | 18 ++++++++++++++++++ include/AudioCodec.h | 1 + 2 files changed, 19 insertions(+) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index c59848764..94d551cbd 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -58,6 +58,8 @@ int I2c_Codec::initCodec() // See the TLV320AIC3106 datasheet for full details of the registers int I2c_Codec::startAudio(int dummy) { + if(verbose) + getParameters().print(); // As a best-practice it's safer not to assume the implementer has issued initCodec() // or has not otherwise modified codec registers since that call. // Explicit Switch to config register page 0: @@ -900,3 +902,19 @@ int I2c_Codec::setMode(std::string parameter) verbose && printf("Codec mode: %d (%s)\n", mode, parameter.c_str()); return 0; } + +#include +void AudioCodecParams::print() +{ +#define P(FIELD) std::cout << #FIELD << ": " << FIELD << "\n" + std::cout << "AudioCodec parameters:\n"; + P(slotSize); + P(startingSlot); + P(bitDelay); + P(mclk); + P(samplingRate); + P(dualRate); + P(tdmMode); + P(generatesBclk); + P(generatesWclk); +}; diff --git a/include/AudioCodec.h b/include/AudioCodec.h index e5c804302..511159dc3 100644 --- a/include/AudioCodec.h +++ b/include/AudioCodec.h @@ -13,6 +13,7 @@ struct AudioCodecParams { bool tdmMode; // whether to use TDM rather than DSP mode bool generatesBclk; // whether the codec generates the bit clock bool generatesWclk; // whether the codec generates the frame sync + void print(); }; class AudioCodec From c7e3ba527b96ccb3f3531cab092dbb5f0631ec3f Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 2 Apr 2021 19:35:00 +0000 Subject: [PATCH 105/148] AudioCodec: added I2S mode --- core/I2c_Codec.cpp | 92 +++++++++++++++++++++----------------- core/I2c_MultiTLVCodec.cpp | 2 +- include/AudioCodec.h | 7 ++- 3 files changed, 58 insertions(+), 43 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 94d551cbd..45d0628ac 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -16,7 +16,10 @@ #include #include -#define TLV320_DSP_MODE +// if only we could be `using` these... +constexpr AudioCodecParams::TdmMode kTdmModeI2s = AudioCodecParams::kTdmModeI2s; +constexpr AudioCodecParams::TdmMode kTdmModeDsp = AudioCodecParams::kTdmModeDsp; +constexpr AudioCodecParams::TdmMode kTdmModeTdm = AudioCodecParams::kTdmModeTdm; I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, CodecType type, bool isVerbose /*= false*/) : codecType(type), dacVolumeHalfDbs(0), adcVolumeHalfDbs(0), hpVolumeHalfDbs(0) @@ -28,7 +31,7 @@ I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, CodecType type, bool isVerbose params.startingSlot = 0; params.bitDelay = 0; params.dualRate = false; - params.tdmMode = false; + params.tdmMode = kTdmModeDsp; params.generatesBclk = true; params.generatesWclk = true; params.mclk = mcaspConfig.getValidAhclk(24000000); @@ -127,46 +130,47 @@ int I2c_Codec::startAudio(int dummy) return 1; // DOUT tri-state when inactive } - if(params.tdmMode) { // Supported values of slot size in the PRU code: 16 and 32 bits. Note that - // altering slot size requires changing #defines in the PRU code. - unsigned int crb; // Audio serial control register B - switch(params.slotSize) {// The below values all enable 256-clock mode when Bclk is an output - case 16: - crb = 0x48; - break; - case 20: - crb = 0x58; - break; - case 24: - crb = 0x68; + // altering slot size may require changing #defines in the PRU code. + unsigned int crb = 0; // Audio serial control register B + switch(params.tdmMode) + { + case kTdmModeI2s: + crb |= 0; + break; + case kTdmModeDsp: + crb |= (1 << 6); // Transfer mode: DSP break; - case 32: - crb = 0x78; + case kTdmModeTdm: + crb |= (1 << 6); // Transfer mode: DSP + crb |= 1 << 3; // enable 256-clock mode when Bclk is an output break; default: return 1; - } - - if(writeRegister(0x09, crb)) // Audio serial control register B: DSP/TDM mode, word len specified by slotSize - return 1; - if(writeRegister(0x0A, params.startingSlot * params.slotSize + params.bitDelay)) // Audio serial control register C: specifying offset in bits - return 1; } - else { -#ifdef TLV320_DSP_MODE // to use with old PRU code - if(writeRegister(0x09, 0x40)) // Audio serial control register B: DSP mode, word len 16 bits -#else - if(writeRegister(0x09, 0x00)) // Audio serial control register B: I2S mode, word len 16 bits -#endif - return 1; -#ifdef TLV320_DSP_MODE // to use with old PRU code - if(writeRegister(0x0A, 0x00)) // Audio serial control register C: 0 bit offset -#else - if(writeRegister(0x0A, 0x01)) // Audio serial control register C: 1 bit offset -#endif - return 1; + unsigned int wlc; // word length control + switch(params.slotSize) { + case 16: + wlc = 0; + break; + case 20: + wlc = 1; + break; + case 24: + wlc = 2; + break; + case 32: + wlc = 3; + break; + default: + return 1; } + crb |= (wlc << 4); + if(writeRegister(0x09, crb)) // Audio serial control register B + return 1; + unsigned int crc = params.startingSlot * params.slotSize + params.bitDelay; + if(writeRegister(0x0A, crc)) // Audio serial control register C: specifying offset in bits + return 1; // clock generation if(params.generatesBclk) { @@ -822,11 +826,17 @@ McaspConfig& I2c_Codec::getMcaspConfig() #define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 2) // AHCLKX and AXR2 outputs */ unsigned int numSlots; - if(params.tdmMode) - // codec is in 256-bit mode - numSlots = 256 / params.slotSize; - else - numSlots = 2; + switch(params.tdmMode) + { + case kTdmModeI2s: + case kTdmModeDsp: + numSlots = 2; + break; + case kTdmModeTdm: + // codec is in 256-bit mode + numSlots = 256 / params.slotSize; + break; + } mcaspConfig.params.inChannels = getNumIns(); mcaspConfig.params.outChannels = getNumOuts();; mcaspConfig.params.inSerializers = {0}; @@ -874,7 +884,7 @@ int I2c_Codec::setParameters(const AudioCodecParams& codecParams) params.bitDelay = 2; ret = -1; } - if(!params.tdmMode && 0 != params.startingSlot) { + if(kTdmModeDsp == params.tdmMode && 0 != params.startingSlot) { verbose && fprintf(stderr, "I2c_Codec: startingSlot has to be 0 in DSP mode\n"); params.startingSlot = 0; ret = -1; diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 0ef0938c0..3d3d41f48 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -128,7 +128,7 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm params.slotSize = tdmConfig.slotSize; params.bitDelay = tdmConfig.bitDelay; params.dualRate = false; - params.tdmMode = true; + params.tdmMode = AudioCodecParams::kTdmModeTdm; params.startingSlot = slotNum; params.generatesBclk = true; params.generatesWclk = primaryCodecGeneratesWclk; diff --git a/include/AudioCodec.h b/include/AudioCodec.h index 511159dc3..c29d19f97 100644 --- a/include/AudioCodec.h +++ b/include/AudioCodec.h @@ -4,13 +4,18 @@ #include "Mcasp.h" struct AudioCodecParams { + typedef enum { + kTdmModeI2s, + kTdmModeDsp, + kTdmModeTdm, + } TdmMode; unsigned int slotSize; // size of a slot in bits unsigned int startingSlot; // what slot in the TDM frame to place the first channel in unsigned int bitDelay; // additional offset in the TDM frame (in bits) double mclk; // frequency of the master clock passed to the codec double samplingRate; // audio sampling rate bool dualRate; // whether to run at single or double sampling rate - bool tdmMode; // whether to use TDM rather than DSP mode + TdmMode tdmMode; // what TDM mode to use bool generatesBclk; // whether the codec generates the bit clock bool generatesWclk; // whether the codec generates the frame sync void print(); From 2a1e8dbe7e801cac0d7712f251ff6ee3e22d567b Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 2 Apr 2021 19:40:44 +0000 Subject: [PATCH 106/148] Mcasp: fixed externalSamplesRisingEdge (it was backwards) --- core/I2c_Codec.cpp | 2 +- core/Mcasp.cpp | 4 ++-- include/Mcasp.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 45d0628ac..780df5fd7 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -850,7 +850,7 @@ McaspConfig& I2c_Codec::getMcaspConfig() mcaspConfig.params.wclkIsInternal = !params.generatesWclk; mcaspConfig.params.wclkIsWord = false; mcaspConfig.params.wclkFalling = false; - mcaspConfig.params.externalRisingEdge = true; + mcaspConfig.params.externalSamplesRisingEdge = false; return mcaspConfig; } diff --git a/core/Mcasp.cpp b/core/Mcasp.cpp index 16da04fe5..6a4638001 100644 --- a/core/Mcasp.cpp +++ b/core/Mcasp.cpp @@ -141,7 +141,7 @@ int McaspConfig::setAclkctl() // 1 Falling edge. External receiver samples data on the rising edge of the // serial clock, so the transmitter must shift data out on the falling edge of // the serial clock. - s.CLKP = !params.externalRisingEdge; + s.CLKP = params.externalSamplesRisingEdge; // ASYNC: Transmit/receive operation asynchronous enable bit. // 0 Synchronous. Transmit clock and frame sync provides the source for both @@ -456,7 +456,7 @@ void McaspConfig::print() P(wclkIsInternal); P(wclkIsWord); P(wclkFalling); - P(externalRisingEdge); + P(externalSamplesRisingEdge); getRegisters(); // update the registers with the current parameters #define R(FIELD) printf("%10s: 0x%08x\n", #FIELD, regs.FIELD) diff --git a/include/Mcasp.h b/include/Mcasp.h index 099eb9a78..07b8e46d5 100644 --- a/include/Mcasp.h +++ b/include/Mcasp.h @@ -45,7 +45,7 @@ class McaspConfig bool wclkIsInternal; bool wclkIsWord; bool wclkFalling; - bool externalRisingEdge; + bool externalSamplesRisingEdge; }; typedef enum { SrctlMode_DISABLED = 0, From 5b92fb2bf510bb6aacdb1e2e8466aaf5c28183bc Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 5 Apr 2021 15:15:36 +0000 Subject: [PATCH 107/148] I2c_Codec: explicitly support I2S, DSP and TDM modes --- core/I2c_Codec.cpp | 53 ++++++++++++++++++++++++-------------- core/I2c_MultiTLVCodec.cpp | 10 +++---- include/AudioCodec.h | 9 +++++-- 3 files changed, 45 insertions(+), 27 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 780df5fd7..211c0f54c 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -20,6 +20,9 @@ constexpr AudioCodecParams::TdmMode kTdmModeI2s = AudioCodecParams::kTdmModeI2s; constexpr AudioCodecParams::TdmMode kTdmModeDsp = AudioCodecParams::kTdmModeDsp; constexpr AudioCodecParams::TdmMode kTdmModeTdm = AudioCodecParams::kTdmModeTdm; +constexpr AudioCodecParams::ClockSource kClockSourceMcasp = AudioCodecParams::kClockSourceMcasp; +constexpr AudioCodecParams::ClockSource kClockSourceCodec = AudioCodecParams::kClockSourceCodec; +constexpr AudioCodecParams::ClockSource kClockSourceExternal = AudioCodecParams::kClockSourceExternal; I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, CodecType type, bool isVerbose /*= false*/) : codecType(type), dacVolumeHalfDbs(0), adcVolumeHalfDbs(0), hpVolumeHalfDbs(0) @@ -32,8 +35,8 @@ I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, CodecType type, bool isVerbose params.bitDelay = 0; params.dualRate = false; params.tdmMode = kTdmModeDsp; - params.generatesBclk = true; - params.generatesWclk = true; + params.bclk = kClockSourceCodec; + params.wclk = kClockSourceCodec; params.mclk = mcaspConfig.getValidAhclk(24000000); params.samplingRate = 44100; initI2C_RW(i2cBus, i2cAddress, -1); @@ -93,7 +96,7 @@ int I2c_Codec::startAudio(int dummy) if(writeRegister(0x02, 0x00)) // Codec sample rate register: fs_ref / 1 return 1; - if(params.generatesBclk) { + if(kClockSourceCodec == params.bclk) { if(setAudioSamplingRate(params.samplingRate)) return 1; } @@ -112,8 +115,8 @@ int I2c_Codec::startAudio(int dummy) return 1; } - if(params.generatesBclk) { - if(params.generatesWclk) { + if(kClockSourceCodec == params.bclk) { + if(kClockSourceCodec == params.wclk) { if(writeRegister(0x08, 0xE0)) { // Audio serial control register A: BCLK, WCLK outputs, return 1; // DOUT tri-state when inactive } @@ -173,7 +176,7 @@ int I2c_Codec::startAudio(int dummy) return 1; // clock generation - if(params.generatesBclk) { + if(kClockSourceCodec == params.bclk) { if(writeRegister(0x66, 0x02)) // Clock generation control register: use MCLK, PLL N = 2 return 1; if(writeRegister(0x65, 0x00)) // GPIO control register B: disabled; codec uses PLLDIV_OUT @@ -220,7 +223,7 @@ int I2c_Codec::startAudio(int dummy) // wait for the codec to stabilize before unmuting the HP amp. // this gets rid of the loud pop. - if(params.generatesBclk) + if(kClockSourceCodec == params.bclk) usleep(10000); // note : a small click persists, but it is unavoidable @@ -768,8 +771,8 @@ int I2c_Codec::disable(){ return 1; if(writeRegister(0x01, 0x80)) // Reset codec to defaults return 1; - if(params.generatesBclk) { - if(params.generatesWclk) { + if(kClockSourceCodec == params.bclk) { + if(kClockSourceCodec == params.wclk) { if(writeRegister(0x08, 0xE0)) { // Put codec in master mode (required for hi-z mode) return 1; } @@ -837,6 +840,7 @@ McaspConfig& I2c_Codec::getMcaspConfig() numSlots = 256 / params.slotSize; break; } + bool isI2s = (kTdmModeI2s == params.tdmMode); mcaspConfig.params.inChannels = getNumIns(); mcaspConfig.params.outChannels = getNumOuts();; mcaspConfig.params.inSerializers = {0}; @@ -844,13 +848,18 @@ McaspConfig& I2c_Codec::getMcaspConfig() mcaspConfig.params.numSlots = numSlots; mcaspConfig.params.slotSize = params.slotSize; mcaspConfig.params.dataSize = params.slotSize; - mcaspConfig.params.bitDelay = params.bitDelay; + // in I2S mode, 0 bitDelay means (10.3.2.3) "the MSB of the left + // channel is valid on the second rising edge of the bit clock after + // the falling edge of the word clock", which - for the McASP - means 1 + // bit delay. + // Therefore in I2s mode the codec always has 1 implicity extra bit delay. + mcaspConfig.params.bitDelay = isI2s ? params.bitDelay + 1 : params.bitDelay; mcaspConfig.params.ahclkIsInternal = true; mcaspConfig.params.ahclkFreq = params.mclk; - mcaspConfig.params.wclkIsInternal = !params.generatesWclk; - mcaspConfig.params.wclkIsWord = false; - mcaspConfig.params.wclkFalling = false; - mcaspConfig.params.externalSamplesRisingEdge = false; + mcaspConfig.params.wclkIsInternal = (kClockSourceMcasp == params.wclk); + mcaspConfig.params.wclkIsWord = isI2s; + mcaspConfig.params.wclkFalling = isI2s; + mcaspConfig.params.externalSamplesRisingEdge = isI2s; return mcaspConfig; } @@ -871,7 +880,7 @@ int I2c_Codec::setParameters(const AudioCodecParams& codecParams) { params = codecParams; int ret = 0; - if(!params.generatesBclk && params.generatesWclk) { + if(kClockSourceCodec != params.bclk && kClockSourceCodec == params.wclk) { verbose && fprintf(stderr, "I2c_Codec: cannot generate Wclk if it doesn't generate Bclk\n"); ret = -1; } @@ -905,10 +914,14 @@ int I2c_Codec::setMode(std::string parameter) mode = InitMode_noDeinit; else if("noInit" == parameter) mode = InitMode_noInit; - else { - mode = InitMode_init; + else if("I2sMain" == parameter || "I2sSecondary" == parameter) + { + params.tdmMode = kTdmModeI2s; + AudioCodecParams::ClockSource cg = ("I2sMain" == parameter) ? kClockSourceCodec : kClockSourceExternal; + params.bclk = cg; + params.wclk = cg; + } else return 1; - } verbose && printf("Codec mode: %d (%s)\n", mode, parameter.c_str()); return 0; } @@ -925,6 +938,6 @@ void AudioCodecParams::print() P(samplingRate); P(dualRate); P(tdmMode); - P(generatesBclk); - P(generatesWclk); + P(bclk); + P(wclk); }; diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 3d3d41f48..623f5b6ed 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -121,7 +121,7 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm #ifdef CODEC_GENERATES_WCLK true; // primaryCodec generates word clock #else - false; // AM335x or external device generates word clock + false; // McASP generates word clock #endif AudioCodecParams params; @@ -130,14 +130,14 @@ I2c_MultiTLVCodec::I2c_MultiTLVCodec(const std::string& cfgString, TdmConfig tdm params.dualRate = false; params.tdmMode = AudioCodecParams::kTdmModeTdm; params.startingSlot = slotNum; - params.generatesBclk = true; - params.generatesWclk = primaryCodecGeneratesWclk; + params.bclk = AudioCodecParams::kClockSourceCodec; + params.wclk = primaryCodecGeneratesWclk ? AudioCodecParams::kClockSourceCodec : AudioCodecParams::kClockSourceMcasp; params.mclk = primaryCodec->getMcaspConfig().getValidAhclk(24000000); params.samplingRate = 44100; primaryCodec->setParameters(params); - params.generatesBclk = false; - params.generatesWclk = false; + params.bclk = AudioCodecParams::kClockSourceExternal; + params.wclk = AudioCodecParams::kClockSourceExternal; for(auto& codec : codecs) { if(codec == primaryCodec) continue; diff --git a/include/AudioCodec.h b/include/AudioCodec.h index c29d19f97..3c8daa846 100644 --- a/include/AudioCodec.h +++ b/include/AudioCodec.h @@ -9,6 +9,11 @@ struct AudioCodecParams { kTdmModeDsp, kTdmModeTdm, } TdmMode; + typedef enum { + kClockSourceMcasp, + kClockSourceCodec, + kClockSourceExternal, + } ClockSource; unsigned int slotSize; // size of a slot in bits unsigned int startingSlot; // what slot in the TDM frame to place the first channel in unsigned int bitDelay; // additional offset in the TDM frame (in bits) @@ -16,8 +21,8 @@ struct AudioCodecParams { double samplingRate; // audio sampling rate bool dualRate; // whether to run at single or double sampling rate TdmMode tdmMode; // what TDM mode to use - bool generatesBclk; // whether the codec generates the bit clock - bool generatesWclk; // whether the codec generates the frame sync + ClockSource bclk; // who generates the bit clock + ClockSource wclk; // who generates the frame sync void print(); }; From 2024b22fff3ffea4e6acf6a1fa868ca73959c714 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 5 Apr 2021 18:26:04 +0000 Subject: [PATCH 108/148] pru_rtaudio_irq: explicitly empty rx FIFO at startup --- pru/pru_rtaudio_irq.p | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 187050d23..22b6b5271 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -1535,10 +1535,20 @@ WRITE_FRAME_MULTI_TLV_LOOP: SUB r2, r2, 1 QBNE WRITE_FRAME_MULTI_TLV_LOOP, r2, 0 + // the RX fifo should be empty according to the docs, but it's not + // always case, so we may end up with an offset of 1*numSerializers + // the below seems to be taking care of that by emptying the FIFO before we start + MOV r2, 0 +WRITE_FRAME_EMPTY_RX: + // read and discard words + FIFO_READ_2_WORDS_AND_PACK r1, r9, r10 + ADD r2, r2, 1 + QBEQ WRITE_FRAME_EMPTY_RX, r2, 128 // 128 is arbitrary. Let's say it's large enough WRITE_FRAME_NOT_MULTI_TLV: #endif /* ENABLE_BELA_GENERIC_TDM */ WRITE_FRAME_DONE: + // 8. Release state machines from reset. // (a) Take the respective state machine(s) out of reset by setting the RSMRST bit // for the receiver and/or the XSMRST bit for the transmitter in GBLCTL. All other From b2c8208f3bcb894fd449b77d1faad1141d897688 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 6 Apr 2021 15:02:26 +0000 Subject: [PATCH 109/148] Mcasp: fixed rotation and clarified dataSize (currently ignored) --- core/Mcasp.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/core/Mcasp.cpp b/core/Mcasp.cpp index 6a4638001..4379177b8 100644 --- a/core/Mcasp.cpp +++ b/core/Mcasp.cpp @@ -43,8 +43,6 @@ int McaspConfig::setFmt() unsigned : 14; } s = {0}; - int rotation = 32 - params.dataSize; - //XDATDLY: 0-3h Transmit sync bit delay. //0 0-bit delay. The first transmit data bit, AXRn, occurs in same ACLKX cycle //as the transmit frame sync (AFSX). @@ -115,12 +113,21 @@ int McaspConfig::setFmt() //5h Rotate right by 20 bit positions. //6h Rotate right by 24 bit positions. //7h Rotate right by 28 bit positions. - if(rotation & 3 || rotation < 0) // has to be a multiple of 4 + if(params.dataSize & 3 || params.dataSize > 32) // has to be a multiple of 4 return -1; - s.ROT = rotation >> 2; + int WORD = 16; // word size is always 16 for the current PRU code, so dataSize is ignored. + int rotation; + // Table 22-9. Transmit Bitstream Data Alignment: + // Tx, MSB first, left-aligned, integer should have XROT=WORD + rotation = WORD; + s.ROT = rotation >> 2; memcpy(®s.xfmt, &s, sizeof(regs.xfmt)); - regs.rfmt = regs.xfmt; + // Table 22-10. Receive Bitstream Data Alignment: + // Rx, MSB first, left-aligned, integer should have XROT=SLOT-WORD + rotation = params.slotSize - WORD; + s.ROT = rotation >> 2; + memcpy(®s.rfmt, &s, sizeof(regs.rfmt)); return 0; } From 9a6d23ff3ad38bd688dd33c9bf833a5f8f06b984 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 6 Apr 2021 15:03:45 +0000 Subject: [PATCH 110/148] pru_rtaudio_irq.p: enabling Tx and Rx sync generators at the same time --- pru/pru_rtaudio_irq.p | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 22b6b5271..52879dfcb 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -1564,8 +1564,7 @@ MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 11) // Set XSMRST // (a) Take the respective frame sync generator(s) out of reset by setting the // RFRST bit for the receiver, and/or the XFRST bit for the transmitter in GBLCTL. // All other bits in GBLCTL should be left at the previous state. -MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 4) // Set RFRST -MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, (1 << 12) // Set XFRST +MCASP_REG_SET_BIT_AND_POLL MCASP_GBLCTL, ((1 << 4) | (1 << 12)) // Set RFRST and XFRST // 10. Upon the first frame sync signal, McASP transfers begin. The McASP // synchronizes to an edge on the frame sync pin, not the level on the frame sync // pin. From 38fb4006dbf4e0e37ddf1e45275b1e49e697db62 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 6 Apr 2021 15:10:10 +0000 Subject: [PATCH 111/148] I2c_MultiTdmCodec: dealing better with clock source --- core/I2c_MultiTdmCodec.cpp | 12 ++++++++---- include/I2c_MultiTLVCodec.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/core/I2c_MultiTdmCodec.cpp b/core/I2c_MultiTdmCodec.cpp index 0b8796fee..cbe49a767 100644 --- a/core/I2c_MultiTdmCodec.cpp +++ b/core/I2c_MultiTdmCodec.cpp @@ -1,7 +1,8 @@ -#include "../include/I2c_MultiTdmCodec.h" +#include "I2c_MultiTdmCodec.h" static const unsigned int minTdmIns = 6; static const unsigned int minTdmOuts = 6; +static const AudioCodecParams::ClockSource kWclkSource = AudioCodecParams::kClockSourceExternal; I2c_MultiTLVCodec::TdmConfig I2c_MultiTdmCodec::makeTdmConfig() { @@ -15,16 +16,19 @@ I2c_MultiTLVCodec::TdmConfig I2c_MultiTdmCodec::makeTdmConfig() I2c_MultiTdmCodec::I2c_MultiTdmCodec(const std::string& cfgString, bool isVerbose) : I2c_MultiTLVCodec(cfgString, makeTdmConfig(), isVerbose) { + auto codecParams = primaryCodec->getParameters(); + codecParams.wclk = kWclkSource; + primaryCodec->setParameters(codecParams); I2c_MultiTLVCodec::getMcaspConfig(); mcaspConfig.params.inSerializers = {0, 1}; mcaspConfig.params.outSerializers = {2, 3}; + mcaspConfig.params.inChannels = getNumIns(); + mcaspConfig.params.outChannels = getNumOuts(); + mcaspConfig.params.wclkIsInternal = AudioCodecParams::kClockSourceMcasp == codecParams.wclk; } McaspConfig& I2c_MultiTdmCodec::getMcaspConfig() { - mcaspConfig.params.inChannels = getNumIns(); - mcaspConfig.params.outChannels = getNumOuts(); - mcaspConfig.params.wclkIsInternal = false; return mcaspConfig; } diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index 7c5208556..57d3400fb 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -52,8 +52,8 @@ class I2c_MultiTLVCodec : public AudioCodec protected: McaspConfig mcaspConfig; -private: std::shared_ptr primaryCodec; // this will be the same as one of the elements of codecs +private: std::vector> codecs; std::vector> disabledCodecs; From e2dc4ca3cad871c3e32a83316e546336478bf274 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 6 Apr 2021 15:18:43 +0000 Subject: [PATCH 112/148] Mcasp: initialised struct and fixed NUMEVT --- core/Mcasp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/Mcasp.cpp b/core/Mcasp.cpp index 4379177b8..097755426 100644 --- a/core/Mcasp.cpp +++ b/core/Mcasp.cpp @@ -328,7 +328,7 @@ uint32_t McaspConfig::computeFifoctl(unsigned int numSerializers) unsigned NUMEVT : 8; unsigned ENA : 1; unsigned : 15; - } s; + } s = {0}; // WENA: Write FIFO enable bit. // 0 Write FIFO is disabled. The WLVL bit in the Write FIFO status register (WFIFOSTS) is reset to 0 // and pointers are initialized, that is, the Write FIFO is “flushed.” @@ -345,7 +345,7 @@ uint32_t McaspConfig::computeFifoctl(unsigned int numSerializers) // 2h 2 words // 3h-40h 3 to 64 words // 41h-FFh Reserved - s.NUMEVT = 0; // TODO: don't know why we keep it this way, but this is what was in our PRU code (as written by @henrix) + s.NUMEVT = numSerializers; // we are not using the DMA events in the PRU code, so this value is unused // 7-0 WNUMDMA 0-FFh Write word count per transfer (32-bit words). Upon a transmit DMA event from the McASP, // WNUMDMA words are transferred from the Write FIFO to the McASP. This value must equal the From 92230dd16eec57c35fa54f069e2e69d51bb84fd0 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Wed, 7 Apr 2021 17:16:12 +0000 Subject: [PATCH 113/148] Mcasp: fail upon illegal setting --- core/Mcasp.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/Mcasp.cpp b/core/Mcasp.cpp index 097755426..796d9cdc3 100644 --- a/core/Mcasp.cpp +++ b/core/Mcasp.cpp @@ -3,6 +3,7 @@ #include #include #include +#include McaspConfig::McaspConfig() { @@ -289,7 +290,11 @@ int McaspConfig::setPdir() // AHCLKX: Determines if AHCLKX pin functions as an input or output. // 0 Pin functions as input. // 1 Pin functions as output. - s.AHCLKX = 1; + s.AHCLKX = params.ahclkIsInternal; + if(!params.ahclkIsInternal) + { + throw std::runtime_error("McASP: external ahclk is unsupported\n"); //TODO: not sure where else we nned to make changes to support it. + } // ACLKX: Determines if ACLKX pin functions as an input or output. // 0 Pin functions as input. // 1 Pin functions as output. From e93620fec622743d903c7fe558020dc8c732c5b7 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 6 Apr 2021 23:01:50 +0000 Subject: [PATCH 114/148] I2c_Codec: also trying Pll settings for D = 0 --- core/I2c_Codec.cpp | 161 ++++++++++++++++++++++++++++++-------------- include/I2c_Codec.h | 1 + 2 files changed, 110 insertions(+), 52 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 211c0f54c..09031d4f6 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -66,6 +66,16 @@ int I2c_Codec::startAudio(int dummy) { if(verbose) getParameters().print(); + bool pllclkInIsBitClock; + if(kClockSourceCodec == params.bclk) { + PLLCLK_IN = params.mclk; + pllclkInIsBitClock = false; + } else { + getMcaspConfig(); // updates mcaspConfig.params.numSlots if needed + unsigned int numSlots = mcaspConfig.params.numSlots; + PLLCLK_IN = params.samplingRate * params.slotSize * numSlots; + pllclkInIsBitClock = true; + } // As a best-practice it's safer not to assume the implementer has issued initCodec() // or has not otherwise modified codec registers since that call. // Explicit Switch to config register page 0: @@ -410,66 +420,106 @@ int I2c_Codec::setPllR(unsigned int r){ return 0; } -int I2c_Codec::setAudioSamplingRate(float newSamplingRate){ - double MHz = 1000000; - double PLLCLK_IN = params.mclk; - - // From the TLV3201AIC3104 datasheet, 10.3.3.1 Audio Clock Generation - // The sampling frequency is given as f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P) - // The master clock PLLCLK_IN is 12MHz - // K is J.D and can be varied in intervals of resolution of 0.0001 up to 63.9999 - - // NOTE: This code does not account for the special case where D = 0 - // which has fewer constrains (useful for clock values such as 2.8224 - // and multiples for 44.1kHz and values such as 1.024MHz and multiples - // for 48kHz (see Table 1. Typical MCLK Rates) +struct PllSettings { + unsigned int P; + unsigned int R; + double K; + double Fs; +}; - //When the PLL is enabled and D ≠ 0000, the following conditions must be satisfied to meet specified - //performance: - //constraint 1: R = 1 - unsigned int R = 1; - //constraint 2: 10 MHz ≤ PLLCLK_IN/P ≤ 20 MHz +std::vector findSettingsWithConstraints( + int Rmin, int Rmax, + double Kmin, double Kmax, + double ratioMin, double ratioMax, + bool integerK, double PLLCLK_IN, + double newSamplingRate + ) +{ + const double MHz = 1000000; + std::vector settings; unsigned int Pmin = 1; unsigned int Pmax = 8; - while(PLLCLK_IN / Pmin > 20*MHz && Pmin <= Pmax) + // constraint: ratioMin Mhz ≤ (PLLCLK_IN/P) ≤ ratioMax MHz + while(PLLCLK_IN / Pmin > ratioMax*MHz && Pmin <= Pmax) ++Pmin; - while(PLLCLK_IN / Pmax < 10*MHz && Pmin <= Pmax) + while(PLLCLK_IN / Pmax < ratioMin*MHz && Pmin <= Pmax) --Pmax; - //constraint 3: 4 ≤ J ≤ 11 (remember that K = J.D) - double Kmin = 4; - double Kmax = 11.9999; - struct PllSettings { - unsigned int P; - unsigned int R; - double K; - double Fs; - }; - std::vector settings; - for(unsigned int P = Pmin; P <= Pmax; ++P) + for(unsigned int R = Rmin; R <= Rmax; ++R) { - //constraint 4: 80 MHz ≤ PLLCLK_IN × K × R/P ≤ 110 MHz - double localKmin = 80*MHz * P / (PLLCLK_IN * R); - double localKmax = 110*MHz * P / (PLLCLK_IN * R); - localKmin = std::max(localKmin, Kmin); - localKmax = std::min(localKmax, Kmax); - // round the Ks up and down to a value with only 4 decimals - localKmin = ((unsigned int)(localKmin * 10000 + 1)) / 10000.0; - localKmax = ((unsigned int)(localKmax * 10000)) / 10000.0; - if(localKmin < localKmax) + for(unsigned int P = Pmin; P <= Pmax; ++P) { - // constrains are met, see if we can find a valid combination of settings - // f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P) - // solve for K and check that it is in the valid range - double K = (newSamplingRate * P * 2048.0/R) / (double)PLLCLK_IN; - // round K to 4 decimals - K = ((unsigned int)(K * 10000 + 0.5)) / 10000.0; - if(K >= localKmin && K <= localKmax) + //80 MHz ≤ PLLCLK_IN × K × R/P ≤ 110 MHz + double localKmin = 80*MHz * P / (PLLCLK_IN * R); + double localKmax = 110*MHz * P / (PLLCLK_IN * R); + localKmin = std::max(localKmin, Kmin); + localKmax = std::min(localKmax, Kmax); + // round the Ks up and down to a value with 4 decimals + localKmin = ((unsigned int)(localKmin * 10000 + 1)) / 10000.0; + localKmax = ((unsigned int)(localKmax * 10000)) / 10000.0; + if(localKmin < localKmax) { - double Fs = (PLLCLK_IN * K * R)/(2048 * P); - settings.push_back({.P = P, .R = R, .K = K, .Fs = Fs}); + // constraints are met, see if we can find a valid combination of settings + // f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P) + // solve for K and check that it is in the valid range + double K = (newSamplingRate * P * 2048.0/R) / (double)PLLCLK_IN; + if(integerK) + // round to int + K = ((unsigned int)(K + 0.5)); + else + // round K to 4 decimals + K = ((unsigned int)(K * 10000 + 0.5)) / 10000.0; + if(K >= localKmin && K <= localKmax) + { + double Fs = (PLLCLK_IN * K * R)/(2048 * P); + settings.push_back({.P = P, .R = R, .K = K, .Fs = Fs}); + } } } } + return settings; +} + +int I2c_Codec::setAudioSamplingRate(float newSamplingRate){ + std::vector settings; + // From the TLV3201AIC3104 datasheet, 10.3.3.1 Audio Clock Generation + // The sampling frequency is given as f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P) + + // • P = 1, 2, 3,…, 8 + // • R = 1, 2, …, 16 + // • K = J.D + // • J = 1, 2, 3, …, 63 + // • D = 0000, 0001, 0002, 0003, …, 9998, 9999 + // • PLLCLK_IN can be MCLK or BCLK, selected by Page 0, register 102, bits D5–D4 + + // When the PLL is enabled and D = 0000, the following conditions must be satisfied to meet specified + // performance: + // constraint 1: 512 kHz ≤ (PLLCLK_IN/P) ≤ 20 MHz + // constraint 2: 4 ≤ J ≤ 55 (remember that K = J.D) + // constraint 3: 80 MHz ≤ (PLLCLK_IN × K × R/P) ≤ 110 MHz + auto newSettings = findSettingsWithConstraints( + 1, 16, // Rmin, Rmax (full range of R values) + 4.0, 55.0, // Kmin, Kmax + 0.512, 20, // ratioMin, ratioMax + true, // only integer values of K (D = 0) + PLLCLK_IN, newSamplingRate + ); + settings.insert(settings.end(), newSettings.begin(), newSettings.end()); + + //When the PLL is enabled and D ≠ 0000, the following conditions must be satisfied to meet specified + //performance: + //constraint 1: R = 1 + //constraint 2: 10 MHz ≤ PLLCLK_IN/P ≤ 20 MHz + //constraint 3: 4 ≤ J ≤ 11 (remember that K = J.D) + //constraint 4: 80 MHz ≤ PLLCLK_IN × K × R/P ≤ 110 MHz + newSettings = findSettingsWithConstraints( + 1, 1, // Rmin, Rmax + 4, 11.9999, // Kmin, Kmax + 10, 20, // ratioMin, ratioMax + false, // fractional values of K allowed + PLLCLK_IN, newSamplingRate + ); + settings.insert(settings.end(), newSettings.begin(), newSettings.end()); + if(0 == settings.size()) { fprintf(stderr, "I2c_Codec: error, no valid PLL settings found\n"); return 1; @@ -484,16 +534,23 @@ int I2c_Codec::setAudioSamplingRate(float newSamplingRate){ optimalSettings = s; } } - // The sampling frequency is given as f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P) if(setPllP(optimalSettings.P)) return 1; if(setPllR(optimalSettings.R)) return 1; - return (setPllK(optimalSettings.K)); + if((setPllK(optimalSettings.K))) + return 1; + PllSettings& s = optimalSettings; + if(verbose) + printf("MCLK: %.4f MHz, fs(ref): %.4f, P: %u, R: %u, J: %d, D: %d, Achieved Fs: %f (err: %.4f%%), \n", + PLLCLK_IN / 1000000, newSamplingRate, + pllP, pllR, pllJ, pllD, + s.Fs, (s.Fs - newSamplingRate) / newSamplingRate * 100 + ); + return 0; } - short unsigned int I2c_Codec::getPllJ(){ return pllJ; } diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index cf9332ea1..9282cbf6b 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -23,6 +23,7 @@ class I2c_Codec : public I2c, public AudioCodec short unsigned int pllD; short unsigned int pllP; short unsigned int pllR; + double PLLCLK_IN; public: typedef enum { TLV320AIC3104 = 0, From 3eb7c52549b0ccb95b0e137fcbf55dfc93934f94 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Tue, 6 Apr 2021 23:44:31 +0000 Subject: [PATCH 115/148] I2c_Codec: use PLL even when bit clock is generated externally. This was required when the external clock generator has fewer than 256 cycles per frame --- core/I2c_Codec.cpp | 57 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 09031d4f6..8f1d3530e 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -66,15 +66,27 @@ int I2c_Codec::startAudio(int dummy) { if(verbose) getParameters().print(); + // setting forceEnablePll = false will attempt (and probably fail) to use clock + // divider instead of PLL when bit clock is generated externally + bool forceEnablePll = true; + bool pllEnabled; bool pllclkInIsBitClock; if(kClockSourceCodec == params.bclk) { + // we generate the bit clock via PLL PLLCLK_IN = params.mclk; pllclkInIsBitClock = false; + pllEnabled = true; } else { getMcaspConfig(); // updates mcaspConfig.params.numSlots if needed unsigned int numSlots = mcaspConfig.params.numSlots; + // bit clock is generated externally. + // Reconstruct its frequency: PLLCLK_IN = params.samplingRate * params.slotSize * numSlots; pllclkInIsBitClock = true; + if(forceEnablePll) + pllEnabled = true; + else + pllEnabled = false; } // As a best-practice it's safer not to assume the implementer has issued initCodec() // or has not otherwise modified codec registers since that call. @@ -106,13 +118,34 @@ int I2c_Codec::startAudio(int dummy) if(writeRegister(0x02, 0x00)) // Codec sample rate register: fs_ref / 1 return 1; - if(kClockSourceCodec == params.bclk) { + if(pllEnabled) { if(setAudioSamplingRate(params.samplingRate)) return 1; - } - else { - // Disable PLL: the codec will be clocked from the bit clock generated by another master - if(writeRegister(0x03, 0x11)) // PLL disable, Q = 2 (fs = CLKIN / 256) + } else { + // when the PLL is disabled, we use the clock divider instead. + // this will only work when the external clock has (n+1)*128 cycles per frame + // 10.3.3.1: + // The audio converters in the TLV320AIC3104 need an internal audio master clock at a frequency of 256*fs(ref), + // which can be obtained in a variety of manners from an external clock signal applied to the device. + // .... + // when the PLL is disabled, fs(ref) = CLKDIV_IN / (128 * Q) + + unsigned int numSlots = mcaspConfig.params.numSlots; + unsigned int Q = (params.slotSize * numSlots) / 128; + // Table 10-9. Page 0, Register 3: PLL Programming Register A + if(Q < 2 || Q > 17) // valid values are 2 to 17, inclusive + { + fprintf(stderr, "I2c_Codec: trying to disable PLL in incompatible mode\n"); + return 1; + } + unsigned int q; + if(Q <= 15) + q = Q; + else + q = Q - 16; + unsigned int pllEnableBit = 0; // clock is generated externally + uint8_t byte = pllEnableBit << 7 | q << 3; + if(writeRegister(0x03, byte)) return 1; } @@ -186,15 +219,14 @@ int I2c_Codec::startAudio(int dummy) return 1; // clock generation - if(kClockSourceCodec == params.bclk) { - if(writeRegister(0x66, 0x02)) // Clock generation control register: use MCLK, PLL N = 2 - return 1; + uint8_t clkSource = pllclkInIsBitClock ? 0x2 : 0x0; // uses BCLK or uses MCLK + uint8_t byte = clkSource << 6 | clkSource << 4 | 2; // CLKDIV_IN, PLLCLK_IN, PLL N = 2 + if(writeRegister(0x66, byte)) + return 1; + if(pllEnabled) { if(writeRegister(0x65, 0x00)) // GPIO control register B: disabled; codec uses PLLDIV_OUT return 1; - } - else { - if(writeRegister(0x66, 0x82)) // Clock generation control register: use BCLK, PLL N = 2 - return 1; + } else { if(writeRegister(0x65, 0x01)) // GPIO control register B: disabled; codec uses CLKDIV_OUT return 1; } @@ -571,7 +603,6 @@ float I2c_Codec::getPllK(){ } float I2c_Codec::getAudioSamplingRate(){ - double PLLCLK_IN = params.mclk; // f_{S(ref)} = (PLLCLK_IN × K × R)/(2048 × P) float fs = (PLLCLK_IN/2048.0) * getPllK()*getPllR()/(float)getPllP(); return fs; From e637fa193d2b4de07219dc80811dcc0a510e3ee8 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 2 Apr 2021 15:40:28 +0000 Subject: [PATCH 116/148] I2c_MultiI2sCodec: codec in I2s mode with an extra pair of data lines for I/O with another I2S device. --- core/I2c_MultiI2sCodec.cpp | 36 ++++++++++++++++++++++++++++++++++++ core/PRU.cpp | 3 +++ core/RTAudio.cpp | 4 ++++ core/board_detect.cpp | 4 ++++ include/Bela.h | 1 + include/I2c_Codec.h | 2 +- include/I2c_MultiI2sCodec.h | 13 +++++++++++++ 7 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 core/I2c_MultiI2sCodec.cpp create mode 100644 include/I2c_MultiI2sCodec.h diff --git a/core/I2c_MultiI2sCodec.cpp b/core/I2c_MultiI2sCodec.cpp new file mode 100644 index 000000000..ea2e5c23a --- /dev/null +++ b/core/I2c_MultiI2sCodec.cpp @@ -0,0 +1,36 @@ +#include "../include/I2c_MultiI2sCodec.h" + +I2c_MultiI2sCodec::I2c_MultiI2sCodec(int i2cBus, int i2cAddress, CodecType type, bool verbose) + : I2c_Codec(i2cBus, i2cAddress, type, verbose), + dataSize(16), + slotSize(16) +{ + setMode("I2sMain"); + AudioCodecParams p = getParameters(); + p.slotSize = slotSize; + setParameters(p); + I2c_Codec::getMcaspConfig(); + mcaspConfig.params.inSerializers = {0, 1}; + mcaspConfig.params.outSerializers = {2, 3}; +} + +McaspConfig& I2c_MultiI2sCodec::getMcaspConfig() +{ + mcaspConfig.params.inChannels = getNumIns(); + mcaspConfig.params.outChannels = getNumOuts(); + mcaspConfig.params.slotSize = slotSize; + mcaspConfig.params.dataSize = dataSize; + return mcaspConfig; +} + +unsigned int I2c_MultiI2sCodec::getNumIns() +{ + unsigned int mul = mcaspConfig.params.inSerializers.size(); + return mul * I2c_Codec::getNumIns(); +} + +unsigned int I2c_MultiI2sCodec::getNumOuts() +{ + unsigned int mul = mcaspConfig.params.outSerializers.size(); + return mul * I2c_Codec::getNumOuts(); +} diff --git a/core/PRU.cpp b/core/PRU.cpp index b4f3f1edb..4e35f1356 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -564,6 +564,7 @@ void PRU::initialisePruCommon(const McaspRegisters& mcaspRegisters) case BelaHw_BelaMiniMultiTdm: case BelaHw_BelaMiniMultiAudio: case BelaHw_BelaMultiTdm: + case BelaHw_BelaMiniMultiI2s: board_flags |= 1 << BOARD_FLAGS_BELA_GENERIC_TDM; break; case BelaHw_CtagFace: @@ -669,6 +670,8 @@ int PRU::start(char * const filename, const McaspRegisters& mcaspRegisters) //nobreak case BelaHw_BelaMultiTdm: //nobreak + case BelaHw_BelaMiniMultiI2s: + //nobreak case BelaHw_CtagFace: //nobreak case BelaHw_CtagBeast: diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 1d9bda0d0..d85b30ecb 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -56,6 +56,7 @@ #include "../include/Spi_Codec.h" #include "../include/I2c_MultiTLVCodec.h" #include "../include/I2c_MultiTdmCodec.h" +#include "../include/I2c_MultiI2sCodec.h" #include "../include/GPIOcontrol.h" extern "C" void enable_runfast(); extern "C" void disable_runfast(); @@ -475,6 +476,8 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) } else if(BelaHw_BelaMiniMultiTdm == belaHw || BelaHw_BelaMultiTdm == belaHw) gAudioCodec = new I2c_MultiTdmCodec(codecMode != "" ? codecMode : "ADDR:2,24,3104,r", gRTAudioVerbose); + else if(BelaHw_BelaMiniMultiI2s == belaHw) + gAudioCodec = new I2c_MultiI2sCodec(codecI2cBus, codecI2cAddress, I2c_Codec::TLV320AIC3104, gRTAudioVerbose); else if(Bela_hwContains(belaHw, Tlv320aic3104)) { gAudioCodec = new I2c_Codec(codecI2cBus, codecI2cAddress, I2c_Codec::TLV320AIC3104, gRTAudioVerbose); @@ -517,6 +520,7 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) break; case BelaHw_CtagFace: case BelaHw_CtagFaceBela: + case BelaHw_BelaMiniMultiI2s: fifoFactor = settings->periodSize / 64; break; case BelaHw_CtagBeast: diff --git a/core/board_detect.cpp b/core/board_detect.cpp index a035e6e2b..3885b88cd 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -22,6 +22,7 @@ static const std::map belaHwMap = { {"BelaMiniMultiAudio", BelaHw_BelaMiniMultiAudio}, {"BelaMiniMultiTdm", BelaHw_BelaMiniMultiTdm}, {"BelaMultiTdm", BelaHw_BelaMultiTdm}, + {"BelaMiniMultiI2s", BelaHw_BelaMiniMultiI2s}, {"Batch", BelaHw_Batch}, }; @@ -207,6 +208,8 @@ bool Bela_checkHwCompatibility(BelaHw userHw, BelaHw detectedHw) return true; else if (userHw == BelaHw_BelaMultiTdm && Bela_hwContains(detectedHw, BelaCape)) return true; + else if (userHw == BelaHw_BelaMiniMultiI2s && Bela_hwContains(detectedHw, BelaMiniCape)) + return true; else if (userHw == BelaHw_BelaMini && Bela_hwContains(detectedHw, BelaMiniCape)) return true; else if (userHw == BelaHw_BelaMiniMultiAudio && Bela_hwContains(detectedHw, BelaMiniCape)) @@ -236,6 +239,7 @@ unsigned int Bela_hwContains(const BelaHw hw, const BelaHwComponent::Component c case BelaHw_BelaMini: case BelaHw_BelaMiniMultiAudio: case BelaHw_BelaMiniMultiTdm: + case BelaHw_BelaMiniMultiI2s: return 1; default: return 0; diff --git a/include/Bela.h b/include/Bela.h index c62779757..3f19caffe 100644 --- a/include/Bela.h +++ b/include/Bela.h @@ -96,6 +96,7 @@ typedef enum BelaHw_BelaMiniMultiAudio, ///< Bela Mini with extra codecs BelaHw_BelaMiniMultiTdm, ///< Bela Mini with extra codecs and/or tdm devices BelaHw_BelaMultiTdm, ///< Bela with extra codecs and/or tdm devices + BelaHw_BelaMiniMultiI2s, ///< Bela Mini with extra rx and tx I2S data lines. BelaHw_Batch, ///< Dummy offline } BelaHw; diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index 9282cbf6b..fca37fb5c 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -72,7 +72,7 @@ class I2c_Codec : public I2c, public AudioCodec I2c_Codec(int i2cBus, int I2cAddress, CodecType type, bool verbose = false); ~I2c_Codec(); - McaspConfig& getMcaspConfig(); + virtual McaspConfig& getMcaspConfig(); int setMode(std::string mode); protected: int configureDCRemovalIIR(bool enable); //called by startAudio() diff --git a/include/I2c_MultiI2sCodec.h b/include/I2c_MultiI2sCodec.h new file mode 100644 index 000000000..743b36696 --- /dev/null +++ b/include/I2c_MultiI2sCodec.h @@ -0,0 +1,13 @@ +#include "I2c_Codec.h" + +class I2c_MultiI2sCodec : public I2c_Codec +{ +public: + I2c_MultiI2sCodec(int i2cBus, int i2cAddress, CodecType type, bool verbose = false); + unsigned int getNumIns() override; + unsigned int getNumOuts() override; + McaspConfig& getMcaspConfig() override; +private: + unsigned int dataSize; + unsigned int slotSize; +}; From 5de68391461538842ab2b60d75034ebe09b9522f Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Wed, 14 Apr 2021 14:36:23 +0000 Subject: [PATCH 117/148] I2c_MultiTLVCodec: removed stale comments --- core/I2c_MultiTLVCodec.cpp | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 623f5b6ed..b1f725d32 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -262,22 +262,6 @@ I2c_MultiTLVCodec::~I2c_MultiTLVCodec() McaspConfig& I2c_MultiTLVCodec::getMcaspConfig() { return mcaspConfig; -/* -// Values below are for 16x 16-bit TDM slots -#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_TX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits -#define BELA_MULTI_TLV_MCASP_ACLKXCTL_VALUE 0x00 // External clk, polarity (falling edge) -#define BELA_MULTI_TLV_MCASP_DATA_FORMAT_RX_VALUE 0x8074 // MSB first, 0 bit delay, 16 bits, DAT bus, ROR 16bits -#define BELA_MULTI_TLV_MCASP_ACLKRCTL_VALUE 0x00 // External clk, polarity (falling edge) -#ifdef CODEC_GENERATES_WCLK -#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x800 // 16-slot TDM external fsclk, rising edge means beginning of frame -#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x800 // 16-slot TDM external fsclk, rising edge means beginning of frame -#define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 2) // AHCLKX and AXR2 outputs -#else // CODEC_GENERATES_WCLK -#define BELA_MULTI_TLV_MCASP_AFSRCTL_VALUE 0x802 // 16-slot TDM internal fsclk, rising edge means beginning of frame -#define BELA_MULTI_TLV_MCASP_AFSXCTL_VALUE 0x802 // 16-slot TDM internal fsclk, rising edge means beginning of frame -#define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | MCASP_PIN_AFSX | (1 << 2) // AHCLKX, FSX, AXR2 outputs -#endif // CODEC_GENERATES_WCLK -*/ } unsigned int I2c_MultiTLVCodec::getNumIns(){ From 2887efb4bc2fa951a48e1b0296771794d611468e Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Wed, 14 Apr 2021 16:15:10 +0000 Subject: [PATCH 118/148] I2c_Codec: setMode() takes a comma separated string --- core/I2c_Codec.cpp | 47 ++++++++++++++++++++++++++++++--------------- include/I2c_Codec.h | 2 +- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 8f1d3530e..f0671881c 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -994,24 +994,39 @@ AudioCodecParams I2c_Codec::getParameters() return params; } -int I2c_Codec::setMode(std::string parameter) +#include "../include/MiscUtilities.h" +int I2c_Codec::setMode(std::string str) { - if("init" == parameter) - mode = InitMode_init; - else if("noDeinit" == parameter) - mode = InitMode_noDeinit; - else if("noInit" == parameter) - mode = InitMode_noInit; - else if("I2sMain" == parameter || "I2sSecondary" == parameter) + std::vector tokens = StringUtils::split(str, ','); + int err = 0; + for(auto parameter : tokens) { - params.tdmMode = kTdmModeI2s; - AudioCodecParams::ClockSource cg = ("I2sMain" == parameter) ? kClockSourceCodec : kClockSourceExternal; - params.bclk = cg; - params.wclk = cg; - } else - return 1; - verbose && printf("Codec mode: %d (%s)\n", mode, parameter.c_str()); - return 0; + parameter = StringUtils::trim(parameter); + if("init" == parameter) + mode = InitMode_init; + else if("noDeinit" == parameter) + mode = InitMode_noDeinit; + else if("noInit" == parameter) + mode = InitMode_noInit; + else if("I2sMain" == parameter || "I2sSecondary" == parameter) + { + params.tdmMode = kTdmModeI2s; + AudioCodecParams::ClockSource cg = ("I2sMain" == parameter) ? kClockSourceCodec : kClockSourceExternal; + params.bclk = cg; + params.wclk = cg; + } else { + ++err; + continue; + } + } + if(verbose) + { + if(err) + fprintf(stderr, "%d error(s) occurred while setting codec to %s\n", err, str.c_str()); + else + printf("Codec mode: %d (%s)\n", mode, str.c_str()); + } + return err; } #include diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index fca37fb5c..809635e8a 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -73,7 +73,7 @@ class I2c_Codec : public I2c, public AudioCodec ~I2c_Codec(); virtual McaspConfig& getMcaspConfig(); - int setMode(std::string mode); + int setMode(std::string str); protected: int configureDCRemovalIIR(bool enable); //called by startAudio() int codecType; From d71ef0e3372ab158555f19fb574ae7cbe0d182f6 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Wed, 14 Apr 2021 16:16:27 +0000 Subject: [PATCH 119/148] I2c_Codec: parametrise differential input mode --- core/I2c_Codec.cpp | 18 ++++++++++++++---- include/I2c_Codec.h | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index f0671881c..8d1099fba 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -28,6 +28,7 @@ I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, CodecType type, bool isVerbose : codecType(type), dacVolumeHalfDbs(0), adcVolumeHalfDbs(0), hpVolumeHalfDbs(0) , running(false) , verbose(isVerbose) + , differentialInput(false) , mode(InitMode_init) { params.slotSize = 16; @@ -234,7 +235,7 @@ int I2c_Codec::startAudio(int dummy) bool dcRemoval; double micBias; - if(codecType == TLV320AIC3104) { + if(!differentialInput) { //Set-up hardware high-pass filter for DC removal dcRemoval = true; micBias = 2.5; @@ -702,11 +703,16 @@ int I2c_Codec::writeADCVolumeRegisters(bool mute) return 1; if(codecType == TLV320AIC3106) { - // Configure inputs as fully differential, weak biasing. + // TODO: 3106/11.3.7 seems to indicate that weakBiasing + // should always be disabled when the channel is + // enabled. For now we keep it enabled for + // differentialInput, pending further testing. + bool weakBiasing = differentialInput; // LINE2L/R connected to corresponding L/R ADC PGA mix with specified gain. - if(writeRegister(0x14, (volumeBits << 3) | 0x84)) + uint8_t byte = (differentialInput << 7) | (volumeBits << 3) | (weakBiasing << 2); + if(writeRegister(0x14, byte)) return 1; - if(writeRegister(0x17, (volumeBits << 3) | 0x84)) + if(writeRegister(0x17, byte)) return 1; } else { // TLV320AIC3104 @@ -1014,6 +1020,10 @@ int I2c_Codec::setMode(std::string str) AudioCodecParams::ClockSource cg = ("I2sMain" == parameter) ? kClockSourceCodec : kClockSourceExternal; params.bclk = cg; params.wclk = cg; + } else if("diff" == parameter) { + differentialInput = true; + } else if("single" == parameter) { + differentialInput = false; } else { ++err; continue; diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index 809635e8a..915b393c0 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -85,6 +85,7 @@ class I2c_Codec : public I2c, public AudioCodec bool running; bool verbose; bool hpEnabled; + bool differentialInput; typedef enum { InitMode_init = 0, From 17189955514bcf9bcb49398565b79dbc84791247 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Wed, 14 Apr 2021 16:17:25 +0000 Subject: [PATCH 120/148] I2c_MultiTLVCodec: pass setMode() to each of the codecs --- core/I2c_MultiTLVCodec.cpp | 6 ++++++ include/I2c_MultiTLVCodec.h | 1 + 2 files changed, 7 insertions(+) diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index b1f725d32..bae416d94 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -283,3 +283,9 @@ float I2c_MultiTLVCodec::getSampleRate() { return primaryCodec->getSampleRate(); return 0; } + +int I2c_MultiTLVCodec::setMode(std::string str) +{ + FOR_EACH_CODEC_DO(setMode(str)); + return 0; +} diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index 57d3400fb..782c8759e 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -39,6 +39,7 @@ class I2c_MultiTLVCodec : public AudioCodec int setHPVolume(int halfDbSteps); int disable(); int reset(); + int setMode(std::string parameter); int numDetectedCodecs(); From 018cea932cffe3ffaa0501695fda5ab3db571703 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Thu, 15 Apr 2021 15:15:19 +0000 Subject: [PATCH 121/148] RTAudioCommandLine: strdup is better --- core/RTAudioCommandLine.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/RTAudioCommandLine.cpp b/core/RTAudioCommandLine.cpp index b4848b864..e78d472e5 100644 --- a/core/RTAudioCommandLine.cpp +++ b/core/RTAudioCommandLine.cpp @@ -327,8 +327,7 @@ int Bela_getopt_long(int argc, char * const argv[], const char *customShortOptio settings->board = getBelaHw(std::string(optarg)); break; case OPT_CODEC_MODE: - settings->codecMode = new char[strlen(optarg) + 1]; - strcpy(settings->codecMode, optarg); + settings->codecMode = strdup(optarg); break; case '?': default: From 48dc7e3ddeee7ddab1eb49df782463e4543c8e34 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Thu, 15 Apr 2021 16:43:36 +0000 Subject: [PATCH 122/148] Setting gains from command line can be done per-channel --- core/I2c_Codec.cpp | 183 +++++++++++++++++++++--------------- core/I2c_MultiTLVCodec.cpp | 33 +++++-- core/RTAudio.cpp | 74 +++++++++++---- core/RTAudioCommandLine.cpp | 146 ++++++++++++++++++++++------ core/Spi_Codec.cpp | 87 ++++++++--------- include/AudioCodec.h | 8 +- include/Bela.h | 73 ++++++++++++-- include/I2c_Codec.h | 23 +++-- include/I2c_MultiTLVCodec.h | 8 +- include/Spi_Codec.h | 10 +- 10 files changed, 440 insertions(+), 205 deletions(-) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 8d1099fba..ab5cf68e6 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -25,7 +25,7 @@ constexpr AudioCodecParams::ClockSource kClockSourceCodec = AudioCodecParams::kC constexpr AudioCodecParams::ClockSource kClockSourceExternal = AudioCodecParams::kClockSourceExternal; I2c_Codec::I2c_Codec(int i2cBus, int i2cAddress, CodecType type, bool isVerbose /*= false*/) -: codecType(type), dacVolumeHalfDbs(0), adcVolumeHalfDbs(0), hpVolumeHalfDbs(0) +: codecType(type) , running(false) , verbose(isVerbose) , differentialInput(false) @@ -277,10 +277,10 @@ int I2c_Codec::startAudio(int dummy) if(writeRegister(0x41, 0x0D)) // HPROUT output level control: output level = 0dB, not muted, powered up return 1; enableLineOut(true); - if(writeDACVolumeRegisters(false)) // Unmute and set volume + if(writeDacVolumeRegisters(false)) // Unmute and set volume return 1; - if(writeADCVolumeRegisters(false)) // Unmute and set ADC volume + if(writeAdcVolumeRegisters(false)) // Unmute and set ADC volume return 1; running = true; @@ -609,85 +609,111 @@ float I2c_Codec::getAudioSamplingRate(){ return fs; } -int I2c_Codec::setPga(float newGain, unsigned short int channel){ - unsigned short int reg; - if(channel == 0) - reg = 0x0F; - else if(channel == 1) - reg = 0x10; - else - return 1; // error, wrong channel - if(newGain > 59.5) +int I2c_Codec::setInputGain(int channel, float gain){ + const uint8_t regLeft = 0x0F; + const uint8_t regRight = 0x10; + std::vector regs; + if(0 == channel) + regs = {regLeft}; + else if(1 == channel) + regs = {regRight}; + else if(channel < 0) + regs = {{regLeft, regRight}}; // both channels + if(gain > 59.5) return 2; // error, gain out of range unsigned short int value; - if(newGain < 0) + if(gain < 0) value = 0b10000000; // PGA is muted else { // gain is adjustable from 0 to 59.5dB in steps of 0.5dB between 0x0 and 0x7f. // Values between 0b01110111 and 0b01111111 are clipped to 59.5dB - value = (int)(newGain * 2 + 0.5) & 0x7f; + value = (int)(gain * 2 + 0.5) & 0x7f; } - return writeRegister(reg, value); + int ret = 0; + for(auto& reg : regs) + ret |= writeRegister(reg, value); + return ret; +} + +template +static int setByChannel(T& dest, const int channel, U val) +{ + if(channel >= (int)dest.size()) + return 1; + for(unsigned int n = 0; n < dest.size(); ++n) + { + if(channel == n || channel < 0) + { + dest[n] = val; + if(channel >= 0) + break; + } + } + return 0; +} + +static int getHalfDbs(float gain) +{ + return floorf(gain * 2.0 + 0.5); } // Set the volume of the DAC output -int I2c_Codec::setDACVolume(int halfDbSteps) +int I2c_Codec::setDacVolume(int channel, float gain) { - dacVolumeHalfDbs = halfDbSteps; + if(setByChannel(dacVolumeHalfDbs, channel, getHalfDbs(gain))) + return 1; if(running) - return writeDACVolumeRegisters(false); - + return writeDacVolumeRegisters(false); return 0; } // Set the volume of the ADC input -int I2c_Codec::setADCVolume(int halfDbSteps) +int I2c_Codec::setAdcVolume(int channel, float gain) { - adcVolumeHalfDbs = halfDbSteps; + if(setByChannel(adcVolumeHalfDbs, channel, getHalfDbs(gain))) + return 1; if(running) - return writeADCVolumeRegisters(false); - + return writeAdcVolumeRegisters(false); return 0; } // Update the DAC volume control registers -int I2c_Codec::writeDACVolumeRegisters(bool mute) +int I2c_Codec::writeDacVolumeRegisters(bool mute) { - int volumeBits = 0; - - if(dacVolumeHalfDbs < 0) { // Volume is specified in half-dBs with 0 as full scale - volumeBits = -dacVolumeHalfDbs; - if(volumeBits > 127) - volumeBits = 127; - } - - if(mute) { - if(writeRegister(0x2B, volumeBits | 0x80)) // Left DAC volume control: muted - return 1; - if(writeRegister(0x2C, volumeBits | 0x80)) // Right DAC volume control: muted - return 1; + std::array volumeBits{}; + for(unsigned int n = 0; n < volumeBits.size(); ++n) + { + // Volume is specified in half-dBs with 0 as full scale + volumeBits[n] = -dacVolumeHalfDbs[n]; + if(volumeBits[n] > 127) + volumeBits[n] = 127; } - else { - if(writeRegister(0x2B, volumeBits)) // Left DAC volume control: not muted - return 1; - if(writeRegister(0x2C, volumeBits)) // Right DAC volume control: not muted + std::array regs = {{ + 0x2B, // Left DAC volume control + 0x2C, // Right DAC volume control + }}; + uint8_t muteBits = mute << 7; + for(unsigned int n = 0; n < regs.size(); ++n) + { + if(writeRegister(regs[n], volumeBits[n] | muteBits)) // DAC volume control return 1; } - return 0; } // Update the ADC volume control registers -int I2c_Codec::writeADCVolumeRegisters(bool mute) +int I2c_Codec::writeAdcVolumeRegisters(bool mute) { - int volumeBits = 0; - + std::array volumeBits{}; // Volume is specified in half-dBs with 0 as full scale // The codec uses 1.5dB steps so we divide this number by 3 - if(adcVolumeHalfDbs < 0) { - volumeBits = -adcVolumeHalfDbs / 3; - if(volumeBits > 8) - volumeBits = 8; + for(unsigned int n = 0; n < volumeBits.size(); ++n) + { + if(adcVolumeHalfDbs[n] < 0) { + volumeBits[n] = -adcVolumeHalfDbs[n] / 3; + if(volumeBits[n] > 8) + volumeBits[n] = 8; + } } if(mute) { @@ -709,16 +735,21 @@ int I2c_Codec::writeADCVolumeRegisters(bool mute) // differentialInput, pending further testing. bool weakBiasing = differentialInput; // LINE2L/R connected to corresponding L/R ADC PGA mix with specified gain. - uint8_t byte = (differentialInput << 7) | (volumeBits << 3) | (weakBiasing << 2); - if(writeRegister(0x14, byte)) - return 1; - if(writeRegister(0x17, byte)) - return 1; + std::array regs = {{ + 0x14, + 0x17, + }}; + for(unsigned int n = 0; n < regs.size(); ++n) + { + uint8_t byte = (differentialInput << 7) | (volumeBits[n] << 3) | (weakBiasing << 2); + if(writeRegister(regs[n], byte)) + return 1; + } } else { // TLV320AIC3104 - if(writeRegister(0x11, (volumeBits << 4) | 0x0F)) // Mic2L (sic) Input connected connected to left-ADC PGA mix with specified gain + if(writeRegister(0x11, (volumeBits[0] << 4) | 0x0F)) // Mic2L (sic) Input connected connected to left-ADC PGA mix with specified gain return 1; - if(writeRegister(0x12, volumeBits | 0xF0)) // Mic2R/Line2R connected to right-ADC PGA mix with specified gain + if(writeRegister(0x12, volumeBits[1] | 0xF0)) // Mic2R/Line2R connected to right-ADC PGA mix with specified gain return 1; } } @@ -727,9 +758,11 @@ int I2c_Codec::writeADCVolumeRegisters(bool mute) } // Set the volume of the headphone output -int I2c_Codec::setHPVolume(int halfDbSteps) +int I2c_Codec::setHpVolume(int channel, float gain) { - hpVolumeHalfDbs = halfDbSteps; + int hd = (int)floorf(gain * 2 + 0.5); + if(setByChannel(hpVolumeHalfDbs, channel, hd)) + return 1; hpEnabled = true; if(running) return writeHPVolumeRegisters(); @@ -749,21 +782,23 @@ int I2c_Codec::enableHpOut(bool enable) // Update the headphone volume control registers int I2c_Codec::writeHPVolumeRegisters() { - int volumeBits = 0; - - if(hpVolumeHalfDbs < 0) { // Volume is specified in half-dBs with 0 as full scale - volumeBits = -hpVolumeHalfDbs; - if(volumeBits > 127) - volumeBits = 127; + std::array regs = {{ + 0x2F, // DAC_L1 to HPLOUT + 0x40, // DAC_R1 to HPROUT + }}; + for(unsigned int n = 0; n < hpVolumeHalfDbs.size(); ++n) + { + int volumeBits = 0; + int hd = hpVolumeHalfDbs[n]; + if(hd < 0) { // Volume is specified in half-dBs with 0 as full scale + volumeBits = -hd; + if(volumeBits > 127) + volumeBits = 127; + } + uint8_t routed = hpEnabled << 7; // DAC_x routed to HPxOUT ? + if(writeRegister(regs[n], volumeBits | routed)) + return 1; } - - // DAC_x routed to HPxOUT ? - char routed = hpEnabled << 7; - if(writeRegister(0x2F, volumeBits | routed)) // DAC_L1 to HPLOUT register - return 1; - if(writeRegister(0x40, volumeBits | routed)) // DAC_R1 to HPROUT register - return 1; - return 0; } @@ -790,9 +825,9 @@ int I2c_Codec::enableLineOut(bool enable) // This tells the codec to stop generating audio and mute the outputs int I2c_Codec::stopAudio() { - if(writeDACVolumeRegisters(true)) // Mute the DACs + if(writeDacVolumeRegisters(true)) // Mute the DACs return 1; - if(writeADCVolumeRegisters(true)) // Mute the ADCs + if(writeAdcVolumeRegisters(true)) // Mute the ADCs return 1; usleep(10000); diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index bae416d94..876a16fac 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -202,27 +202,42 @@ int I2c_MultiTLVCodec::stopAudio() return 0; } -int I2c_MultiTLVCodec::setPga(float newGain, unsigned short int channel) +#define FOR_CODEC_CHANNEL_DO(do) {\ + if(channel < 0) /* all channels on all codecs*/\ + {\ + int ret = 0;\ + for(auto& c : codecs)\ + ret |= c->do;\ + return ret;\ + }\ + int cod = channel / 2;\ + channel = channel % 2;\ + if(cod >= codecs.size())\ + return -1;\ + codecs[cod]->do;\ + return 0;\ +} + +int I2c_MultiTLVCodec::setInputGain(int channel, float gain) { - FOR_EACH_CODEC_DO(setPga(newGain, channel)); - return 0; + FOR_CODEC_CHANNEL_DO(setInputGain(channel, gain)); } -int I2c_MultiTLVCodec::setDACVolume(int halfDbSteps) +int I2c_MultiTLVCodec::setDacVolume(int channel, float gain) { - FOR_EACH_CODEC_DO(setDACVolume(halfDbSteps)); + FOR_CODEC_CHANNEL_DO(setDacVolume(channel, gain)); return 0; } -int I2c_MultiTLVCodec::setADCVolume(int halfDbSteps) +int I2c_MultiTLVCodec::setAdcVolume(int channel, float gain) { - FOR_EACH_CODEC_DO(setADCVolume(halfDbSteps)); + FOR_CODEC_CHANNEL_DO(setAdcVolume(channel, gain)); return 0; } -int I2c_MultiTLVCodec::setHPVolume(int halfDbSteps) +int I2c_MultiTLVCodec::setHpVolume(int channel, float gain) { - FOR_EACH_CODEC_DO(setHPVolume(halfDbSteps)); + FOR_CODEC_CHANNEL_DO(setHpVolume(channel, gain)); return 0; } diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index d85b30ecb..321ede30f 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -128,6 +128,7 @@ int gRTAudioVerbose = 0; // Verbosity level for debugging AudioCodec* gAudioCodec = NULL; static AudioCodec* gDisabledCodec = NULL; static BelaHw belaHw; +extern const float BELA_INVALID_GAIN; static int Bela_getHwConfigPrivate(BelaHw hw, BelaHwConfig* cfg, BelaHwConfigPrivate* pcfg) { @@ -265,6 +266,17 @@ static int batchCallbackLoop(InternalBelaContext* context, void (*render)(BelaCo return 0; } +static int setChannelGains(BelaChannelGainArray& cga, int (*cb)(int, float)) +{ + for(unsigned int n = 0; n < cga.length; n++) + { + BelaChannelGain& cg = cga.data[n]; + int ret = cb(cg.channel, cg.gain); + if(ret) + return ret; + } + return 0; +} int Bela_initAudio(BelaInitSettings *settings, void *userData) { @@ -642,18 +654,31 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) return 1; } - // Set default volume levels - Bela_setDACLevel(settings->dacLevel); - Bela_setADCLevel(settings->adcLevel); // TODO: add more argument checks - for(int n = 0; n < 2; n++){ - if(settings->pgaGain[n] > 59.5){ - fprintf(stderr, "PGA gain out of range [0,59.5] for channel %d: %fdB\n", n, settings->pgaGain[n]); - return 1; - } - Bela_setPgaGain(settings->pgaGain[n], n); + + if(setChannelGains(settings->audioInputGains, Bela_setAudioInputGain)) + return 1; + if(setChannelGains(settings->headphoneGains, Bela_setHpLevel)) + return 1; + if(setChannelGains(settings->dacGains, Bela_setDacLevel)) + return 1; + if(setChannelGains(settings->adcGains, Bela_setAdcLevel)) + return 1; + + // These are deprecated. We keep them for bw compatibilty. + // will be removed later. + // They have to come after the newer ones above + for(unsigned int n = 0; n < 2; n++) + { + if(BELA_INVALID_GAIN != settings->pgaGain[n]) + Bela_setPgaGain(settings->pgaGain[n], n); // DEPRECATED } - Bela_setHeadphoneLevel(settings->headphoneLevel); + if(BELA_INVALID_GAIN != settings->headphoneLevel) + Bela_setHeadphoneLevel(settings->headphoneLevel); // DEPRECATED + if(BELA_INVALID_GAIN != settings->dacLevel) + Bela_setDACLevel(settings->dacLevel); // DEPRECATED + if(BELA_INVALID_GAIN != settings->adcLevel) + Bela_setADCLevel(settings->adcLevel); // DEPRECATED gBlockDurationMs = gUserContext->audioFrames / gUserContext->audioSampleRate * 1000; // Call the user-defined initialisation function @@ -957,10 +982,15 @@ int Bela_stopRequested() // Set the level of the DAC; affects all outputs (headphone, line, speaker) // 0dB is the maximum, -63.5dB is the minimum; 0.5dB steps int Bela_setDACLevel(float decibels) +{ + return Bela_setDacLevel(-1, decibels); +} + +int Bela_setDacLevel(int channel, float decibels) { if(gAudioCodec == 0) return -1; - return gAudioCodec->setDACVolume((int)floorf(decibels * 2.0 + 0.5)); + return gAudioCodec->setDacVolume(channel, decibels); return 0; } @@ -969,30 +999,42 @@ int Bela_setDACLevel(float decibels) // 0dB is the maximum, -12dB is the minimum; 1.5dB steps int Bela_setADCLevel(float decibels) { + return Bela_setAdcLevel(-1, decibels); +} +int Bela_setAdcLevel(int channel, float decibels) +{ if(gAudioCodec == 0) return -1; - return gAudioCodec->setADCVolume((int)floorf(decibels * 2.0 + 0.5)); + return gAudioCodec->setAdcVolume(channel, decibels); } // Set the level of the Programmable Gain Amplifier // 59.5dB is maximum, 0dB is minimum; 0.5dB steps int Bela_setPgaGain(float decibels, int channel){ + return Bela_setAudioInputGain(channel, decibels); +} + +int Bela_setAudioInputGain(int channel, float decibels){ if(gAudioCodec == 0) return -1; - return gAudioCodec->setPga(decibels, channel); + return gAudioCodec->setInputGain(channel, decibels); } // Set the level of the onboard headphone amplifier; affects headphone // output only (not line out or speaker) // 0dB is the maximum, -63.5dB is the minimum; 0.5dB steps -int Bela_setHeadphoneLevel(float decibels) +int Bela_setHpLevel(int channel, float decibels) { - if(gAudioCodec == 0) return -1; - return gAudioCodec->setHPVolume((int)floorf(decibels * 2.0 + 0.5)); + return gAudioCodec->setHpVolume(channel, decibels); +} + +int Bela_setHeadphoneLevel(float decibels) +{ + return Bela_setHpLevel(-1, decibels); } // Mute or unmute the onboard speaker amplifiers diff --git a/core/RTAudioCommandLine.cpp b/core/RTAudioCommandLine.cpp index e78d472e5..ebbc2f0c9 100644 --- a/core/RTAudioCommandLine.cpp +++ b/core/RTAudioCommandLine.cpp @@ -10,22 +10,30 @@ #include "../include/bela_sw_settings.h" #include "../include/MiscUtilities.h" -#define OPT_PRU_FILE 1000 -#define OPT_PGA_GAIN_LEFT 1001 -#define OPT_PGA_GAIN_RIGHT 1002 -#define OPT_PRU_NUMBER 1003 -#define OPT_DISABLE_LED 1004 -#define OPT_STOP_BUTTON_PIN 1005 -#define OPT_DETECT_UNDERRUNS 1006 -#define OPT_UNIFORM_SAMPLE_RATE 1007 -#define OPT_HIGH_PERFORMANCE_MODE 1008 -#define OPT_BOARD 1009 -#define OPT_CODEC_MODE 1010 +enum { + OPT_PRU_FILE = 1000, + OPT_PGA_GAIN_LEFT, + OPT_PGA_GAIN_RIGHT, + OPT_PRU_NUMBER, + OPT_DISABLE_LED, + OPT_STOP_BUTTON_PIN, + OPT_DETECT_UNDERRUNS, + OPT_UNIFORM_SAMPLE_RATE, + OPT_HIGH_PERFORMANCE_MODE, + OPT_BOARD, + OPT_CODEC_MODE, +}; + +extern const float BELA_INVALID_GAIN = 99999999999; // whether it's the first time that Bela_getopt_long is run static bool gFirstRun = 1; -bool parseAudioExpanderChannels(const char *arg, bool inputChannel, BelaInitSettings *settings); +static bool parseAdcLevels(const char* arg, BelaInitSettings* settings); +static bool parseDacLevels(const char* arg, BelaInitSettings* settings); +static bool parseAudioInputGains(const char *arg, BelaInitSettings *settings); +static bool parseHeadphoneLevels(const char *arg, BelaInitSettings *settings); +static bool parseAudioExpanderChannels(const char *arg, bool inputChannel, BelaInitSettings *settings); // Default command-line options for RTAudio struct option gDefaultLongOptions[] = @@ -41,6 +49,7 @@ struct option gDefaultLongOptions[] = {"adc-level", 1, NULL, 'A'}, {"pga-gain-left", 1, NULL, OPT_PGA_GAIN_LEFT}, {"pga-gain-right", 1, NULL, OPT_PGA_GAIN_RIGHT}, + {"audio-input-gain", 1, NULL, 'I'}, {"hp-level", 1, NULL, 'H'}, {"mux-channels", 1, NULL, 'X'}, {"audio-expander-inputs", 1, NULL, 'Y'}, @@ -57,8 +66,12 @@ struct option gDefaultLongOptions[] = {NULL, 0, NULL, 0} }; -const char gDefaultShortOptions[] = "p:vN:M:C:D:A:H:G:B:X:Y:Z:"; +const char gDefaultShortOptions[] = "p:vN:M:C:D:A:I:H:G:B:X:Y:Z:"; +static void deprecatedWarning(const char* call, const char* newOne) +{ + std::cerr << "Warning: " << call << " is deprecated. Use " << newOne << " instead\n"; +} BelaInitSettings* Bela_InitSettings_alloc() { @@ -88,11 +101,15 @@ void Bela_defaultSettings(BelaInitSettings *settings) settings->numDigitalChannels = 16; settings->beginMuted = 0; - settings->dacLevel = DEFAULT_DAC_LEVEL; - settings->adcLevel = DEFAULT_ADC_LEVEL; + settings->dacLevel = BELA_INVALID_GAIN; + settings->adcLevel = BELA_INVALID_GAIN; for(int n = 0; n < 2; n++) - settings->pgaGain[n] = DEFAULT_PGA_GAIN; - settings->headphoneLevel = DEFAULT_HP_LEVEL; + settings->pgaGain[n] = BELA_INVALID_GAIN; + settings->headphoneLevel = BELA_INVALID_GAIN; + parseAudioInputGains("", settings); + parseHeadphoneLevels("", settings); + parseAdcLevels("", settings); + parseDacLevels("", settings); settings->numMuxChannels = 0; settings->audioExpanderInputs = 0; settings->audioExpanderOutputs = 0; @@ -274,13 +291,18 @@ int Bela_getopt_long(int argc, char * const argv[], const char *customShortOptio settings->beginMuted = atoi(optarg); break; case 'D': - settings->dacLevel = atof(optarg); + parseDacLevels(optarg, settings); break; case 'A': - settings->adcLevel = atof(optarg); + parseAdcLevels(optarg, settings); break; case 'H': - settings->headphoneLevel = atof(optarg); + if(!parseHeadphoneLevels(optarg, settings)) + std::cerr << "Warning: invalid headphone level settings '" << optarg << "'-- ignoring\n"; + break; + case 'I': + if(!parseAudioInputGains(optarg, settings)) + std::cerr << "Warning: invalid audio input gain settings '" << optarg << "'-- ignoring\n"; break; case 'X': settings->numMuxChannels = atoi(optarg); @@ -300,10 +322,12 @@ int Bela_getopt_long(int argc, char * const argv[], const char *customShortOptio std::cerr << "Warning: filename for the PRU code is too long (>" << MAX_PRU_FILENAME_LENGTH << " characters). Using embedded PRU code instead\n"; break; case OPT_PGA_GAIN_LEFT: - settings->pgaGain[0] = atof(optarg); + deprecatedWarning("--pga-gain-left", "--audio-input-gain"); + parseAudioInputGains((std::string("0,") + optarg).c_str(), settings); break; case OPT_PGA_GAIN_RIGHT: - settings->pgaGain[1] = atof(optarg); + deprecatedWarning("--pga-gain-right", "--audio-input-gain"); + parseAudioInputGains((std::string("1,") + optarg).c_str(), settings); break; case OPT_PRU_NUMBER: settings->pruNumber = atoi(optarg); @@ -341,11 +365,12 @@ int Bela_getopt_long(int argc, char * const argv[], const char *customShortOptio void Bela_usage() { std::cerr << " --period [-p] period: Set the hardware period (buffer) size in audio samples\n"; - std::cerr << " --dac-level [-D] dBs: Set the DAC output level (0dB max; -63.5dB min)\n"; - std::cerr << " --adc-level [-A] dBs: Set the ADC input level (0dB max; -12dB min)\n"; - std::cerr << " --pga-gain-left dBs: Set the Programmable Gain Amplifier for the left audio channel (0dBmin; 59.5dB max; default: 16dB)\n"; - std::cerr << " --pga-gain-right dBs: Set the Programmable Gain Amplifier for the right audio channel (0dBmin; 59.5dB max; default: 16dB)\n"; - std::cerr << " --hp-level [-H] dBs: Set the headphone output level (0dB max; -63.5dB min)\n"; + std::cerr << " --dac-level [-D] dBs: changains Set the DAC output level (0dB max; -63.5dB min)\n"; + std::cerr << " --adc-level [-A] dBs: changains Set the ADC input level (0dB max; -12dB min)\n"; + std::cerr << " --pga-gain-left dBs: Set the Programmable Gain Amplifier for the left audio channel (0dBmin; 59.5dB max; default: " << DEFAULT_PGA_GAIN << " dB). DEPRECATED: use --audio-input-gain instead\n"; + std::cerr << " --pga-gain-right dBs: Set the Programmable Gain Amplifier for the right audio channel (0dBmin; 59.5dB max; default:" << DEFAULT_PGA_GAIN << " dB). DEPRECATED: Use --audio-input-gain instead\n"; + std::cerr << " --audio-input-gain [-I] changains: Set the gain for the specified audio input channels (gain: 0dB min; 59.5dB max); default: " << DEFAULT_PGA_GAIN << " dB)\n"; + std::cerr << " --hp-level [-H] changains: Set the headphone output level (gain: 0dB max; -63.5dB min)\n"; std::cerr << " --mute-speaker [-M] val: Set whether to mute the speaker initially (default: no)\n"; std::cerr << " --use-analog [-N] val: Set whether to use ADC/DAC analog (default: yes)\n"; std::cerr << " --use-digital [-G] val: Set whether to use digital GPIO channels (default: yes)\n"; @@ -367,6 +392,7 @@ void Bela_usage() std::cerr << " --board val: Select a different board to work with\n"; std::cerr << " --codec-mode val: A codec-specific string representing an intialisation parameter\n"; std::cerr << " --verbose [-v]: Enable verbose logging information\n"; + std::cerr << " `changains` must be one or more `channel,gain` pairs. A negative channel number means all channels. A single value is interpreted as gain, with channel=-1\n"; } // ---- internal functions ---- @@ -392,6 +418,72 @@ bool parseCommaSeparatedList(const char *in, std::vector& tokens) { return true; } +// append values to vec, or updates gains for existing channels. In case of error, vec is unmodified. +// Sets cga based on the final content of vec +static bool parseChannelGainPairs(BelaChannelGainArray& cga, std::vector& vec, const char* arg) +{ + std::vector strs = StringUtils::split(arg, ','); + // channel,gain pairs + if(strs.size() % 2) { + if(1 == strs.size()) { + // single value x is equivalent to `-1,x` + strs = {"-1", strs[0]}; + } else { + // odd, non-1 count: bad format + return false; + } + } + std::vector newCg = vec; + for(unsigned int n = 0; n < strs.size() / 2; ++n) + { + int channel = atoi(strs[n * 2].c_str()); + float gain = atof(strs[n * 2 + 1].c_str()); + // remove any old value(s) for the channel + // before appending the new value + for(auto m = newCg.begin(); m < newCg.end();) + { + if(m->channel == channel) + { + newCg.erase(m); + } + else + ++m; + } + newCg.push_back({ + .channel = channel, + .gain = gain, + }); + } + vec = newCg; + cga.length = vec.size(); + cga.data = vec.data(); + return true; +} + +static bool parseAdcLevels(const char* arg, BelaInitSettings* settings) +{ + static std::vector cg = {{ .channel = -1, .gain = DEFAULT_ADC_LEVEL, }}; + return parseChannelGainPairs(settings->adcGains, cg, arg); +} + +static bool parseDacLevels(const char* arg, BelaInitSettings* settings) +{ + static std::vector cg = {{ .channel = -1, .gain = DEFAULT_DAC_LEVEL, }}; + return parseChannelGainPairs(settings->dacGains, cg, arg); +} + +static bool parseHeadphoneLevels(const char* arg, BelaInitSettings* settings) +{ + static std::vector cg = {{ .channel = -1, .gain = DEFAULT_HP_LEVEL, }}; + return parseChannelGainPairs(settings->headphoneGains, cg, arg); +} + +static bool parseAudioInputGains(const char* arg, BelaInitSettings* settings) +{ + static std::vector cg = {{ .channel = -1, .gain = DEFAULT_PGA_GAIN, }}; + return parseChannelGainPairs(settings->audioInputGains, cg, arg); +} + // Parse the argument for the audio expander channels to enable bool parseAudioExpanderChannels(const char *arg, bool inputChannel, BelaInitSettings *settings) { std::vector channels; diff --git a/core/Spi_Codec.cpp b/core/Spi_Codec.cpp index 3b67ce3a6..6afa20f60 100644 --- a/core/Spi_Codec.cpp +++ b/core/Spi_Codec.cpp @@ -15,6 +15,7 @@ const int RESET_PIN = 81; // GPIO2(17) P8.34 #include #include #include +#include Spi_Codec::Spi_Codec(const char* spidev_gpio_cs0, const char* spidev_gpio_cs1, bool isVerbose /* = false */) { @@ -50,6 +51,7 @@ Spi_Codec::Spi_Codec(const char* spidev_gpio_cs0, const char* spidev_gpio_cs1, b usleep(10000); // now we can detect if there is a slave codec _isBeast = slaveIsDetected(); + _dacVolumethreeEighthsDbs.resize(_isBeast ? 16 : 8); } Spi_Codec::~Spi_Codec(){ @@ -189,9 +191,15 @@ int Spi_Codec::stopAudio(){ return writeRegister(REG_PLL_CLK_CONTROL_0, 0x9D); } -int Spi_Codec::setDACVolume(int halfDbSteps){ - // Calculcate volume from half dB in 3/8 dB steps und cast to int - _dacVolumethreeEighthsDbs = (int) ((float) halfDbSteps * (1.0 + 1.0/3.0)); +int Spi_Codec::setDacVolume(const int channel, float gain) { + if(channel >= int(_dacVolumethreeEighthsDbs.size())) + return 1; + // Calculcate volume from gain dB in 3/8 dB steps und cast to int + for(unsigned int n = 0; n < _dacVolumethreeEighthsDbs.size(); ++n) + { + if(channel < 0 || channel == n) + _dacVolumethreeEighthsDbs[n] = (int) ((float) (gain * 2) * (1.0 + 1.0/3.0)); + } return _writeDACVolumeRegisters(false); } @@ -245,12 +253,14 @@ int Spi_Codec::reset(){ } int Spi_Codec::_writeDACVolumeRegisters(bool mute){ - unsigned char volumeBits = 0; - - if (_dacVolumethreeEighthsDbs < 0){ - volumeBits = -_dacVolumethreeEighthsDbs; - if (_dacVolumethreeEighthsDbs > 95) - volumeBits = 255; + std::vector volumeBits(_dacVolumethreeEighthsDbs.size()); + for(unsigned int n = 0; n > volumeBits.size(); ++n) + { + if (_dacVolumethreeEighthsDbs[n] < 0){ + volumeBits[n] = -_dacVolumethreeEighthsDbs[n]; + if (_dacVolumethreeEighthsDbs[n] > 95) + volumeBits[n] = 255; + } } if (mute){ @@ -262,43 +272,28 @@ int Spi_Codec::_writeDACVolumeRegisters(bool mute){ } } else { - if (writeRegister(REG_DAC_VOLUME_L1, volumeBits, MASTER_CODEC)) - return 1; - if (writeRegister(REG_DAC_VOLUME_R1, volumeBits, MASTER_CODEC)) - return 1; - if (writeRegister(REG_DAC_VOLUME_L2, volumeBits, MASTER_CODEC)) - return 1; - if (writeRegister(REG_DAC_VOLUME_R2, volumeBits, MASTER_CODEC)) - return 1; - if (writeRegister(REG_DAC_VOLUME_L3, volumeBits, MASTER_CODEC)) - return 1; - if (writeRegister(REG_DAC_VOLUME_R3, volumeBits, MASTER_CODEC)) - return 1; - if (writeRegister(REG_DAC_VOLUME_L4, volumeBits, MASTER_CODEC)) - return 1; - if (writeRegister(REG_DAC_VOLUME_R4, volumeBits, MASTER_CODEC)) - return 1; - if (writeRegister(REG_DAC_CHANNEL_MUTES, 0x0, MASTER_CODEC)) // Unmute all DACs - return 1; - if(_isBeast) { - if (writeRegister(REG_DAC_VOLUME_L1, volumeBits, SLAVE_CODEC)) - return 1; - if (writeRegister(REG_DAC_VOLUME_R1, volumeBits, SLAVE_CODEC)) - return 1; - if (writeRegister(REG_DAC_VOLUME_L2, volumeBits, SLAVE_CODEC)) - return 1; - if (writeRegister(REG_DAC_VOLUME_R2, volumeBits, SLAVE_CODEC)) - return 1; - if (writeRegister(REG_DAC_VOLUME_L3, volumeBits, SLAVE_CODEC)) - return 1; - if (writeRegister(REG_DAC_VOLUME_R3, volumeBits, SLAVE_CODEC)) - return 1; - if (writeRegister(REG_DAC_VOLUME_L4, volumeBits, SLAVE_CODEC)) - return 1; - if (writeRegister(REG_DAC_VOLUME_R4, volumeBits, SLAVE_CODEC)) - return 1; - // Unmute all DACs - if (writeRegister(REG_DAC_CHANNEL_MUTES, 0x0, SLAVE_CODEC)) + std::array regsDacVolume = {{ + REG_DAC_VOLUME_L1, + REG_DAC_VOLUME_R1, + REG_DAC_VOLUME_L2, + REG_DAC_VOLUME_R2, + REG_DAC_VOLUME_L3, + REG_DAC_VOLUME_R3, + REG_DAC_VOLUME_L4, + REG_DAC_VOLUME_R4, + }}; + std::array codecs = {{ + MASTER_CODEC, + SLAVE_CODEC, + }}; + for(unsigned int c = 0; c < _isBeast + 1; ++c) + { + for(unsigned int n = 0; n < volumeBits.size() && n < regsDacVolume.size(); ++n) + { + if (writeRegister(regsDacVolume[n], volumeBits[n], codecs[c])) + return 1; + } + if (writeRegister(REG_DAC_CHANNEL_MUTES, 0x0, codecs[c])) // Unmute all DACs return 1; } } diff --git a/include/AudioCodec.h b/include/AudioCodec.h index 3c8daa846..968b5f06b 100644 --- a/include/AudioCodec.h +++ b/include/AudioCodec.h @@ -36,10 +36,10 @@ class AudioCodec virtual unsigned int getNumIns() = 0; virtual unsigned int getNumOuts() = 0; virtual float getSampleRate() = 0; - virtual int setPga(float newGain, unsigned short int channel) = 0; - virtual int setDACVolume(int halfDbSteps) = 0; - virtual int setADCVolume(int halfDbSteps) = 0; - virtual int setHPVolume(int halfDbSteps) = 0; + virtual int setInputGain(int channel, float newGain) = 0; + virtual int setDacVolume(int channel, float gain) = 0; + virtual int setAdcVolume(int channel, float gain) = 0; + virtual int setHpVolume(int channel, float gain) = 0; virtual int disable() = 0; virtual int reset() = 0; virtual int setMode(std::string parameter) {return 0;}; diff --git a/include/Bela.h b/include/Bela.h index 3f19caffe..e9e9eaf42 100644 --- a/include/Bela.h +++ b/include/Bela.h @@ -27,10 +27,16 @@ #ifndef BELA_H_ #define BELA_H_ #define BELA_MAJOR_VERSION 1 -#define BELA_MINOR_VERSION 10 +#define BELA_MINOR_VERSION 11 #define BELA_BUGFIX_VERSION 0 // Version history / changelog: +// 1.11.0 +// - added BelaChannelGain and BelaChannelGainArray +// - added setHpLevel(), setAudioInputGain(), setAdcLevel(), setDacLevel(), +// deprecated the functions they are intended to replace +// - added the corresponding fields in BelaInitSettings: headphoneGains, +// audioInputGains, adcGains, dacGains // 1.10.0 // - added parameter to Bela_detectHw(), and associated typedef // - added more values to the BelaHw enum @@ -141,7 +147,7 @@ typedef enum /** \cond PRIVATE */ #define MAX_PRU_FILENAME_LENGTH 256 -#define MAX_UNUSED2_LENGTH 256 +#define MAX_UNUSED_LENGTH 224 #define MAX_PROJECTNAME_LENGTH 256 /** \endcond */ @@ -403,6 +409,15 @@ typedef struct { const unsigned int underrunCount; } BelaContext; +struct BelaChannelGain { + int channel; ///< Channel number. Negative value means all the channels + float gain; ///< Gain in dB. +}; + +struct BelaChannelGainArray { + unsigned int length; + struct BelaChannelGain* data; +}; /** * \ingroup control * \brief Structure containing initialisation parameters for the real-time @@ -438,13 +453,13 @@ typedef struct { /// Whether to begin with the speakers muted int beginMuted; - /// Level for the audio DAC output + /// Level for the audio DAC output. DEPRECATED: ues dacGains float dacLevel; - /// Level for the audio ADC input + /// Level for the audio ADC input. DEPRECATED: use adcGains float adcLevel; - /// Gains for the PGA, left and right channels + /// Gains for the PGA, left and right channels. DEPRECATED: use audioInputGains float pgaGain[2]; - /// Level for the headphone output + /// Level for the headphone output. DEPRECATED: use headphoneGains float headphoneLevel; /// How many channels to use on the multiplexer capelet, if enabled int numMuxChannels; @@ -506,7 +521,16 @@ typedef struct { void (*audioThreadDone)(BelaContext*, void*); /// A codec-specific intialisation parameter char* codecMode; - char unused2[MAX_UNUSED2_LENGTH]; + /// audio input gains + struct BelaChannelGainArray audioInputGains; + /// level for headphone outputs + struct BelaChannelGainArray headphoneGains; + /// Level for the audio ADC input + struct BelaChannelGainArray adcGains; + /// Level for the audio DAC output + struct BelaChannelGainArray dacGains; + + char unused[MAX_UNUSED_LENGTH]; /// User selected board to work with (as opposed to detected hardware). BelaHw board; @@ -829,11 +853,19 @@ int Bela_stopRequested(); * \b Important: do not call this function from within render(), as it does not make * any guarantees on real-time performance. * + * \param channel The channel to set. Use a negative value to set all channels. * \param decibels Level of the DAC output. Valid levels range from -63.5 (lowest) to * 0 (highest) in steps of 0.5dB. Levels between increments of 0.5 will be rounded down. * * \return 0 on success, or nonzero if an error occurred. */ +int Bela_setDacLevel(int channel, float decibels); + +/** + * DEPRECATED. + * + * Equivalent to `Bela_setDacLevel(-1, decibels)`. + */ int Bela_setDACLevel(float decibels); /** @@ -845,16 +877,24 @@ int Bela_setDACLevel(float decibels); * \b Important: do not call this function from within render(), as it does not make * any guarantees on real-time performance. * + * \param channel The channel to set. Use a negative value to set all channels. * \param decibels Level of the ADC input. Valid levels range from -12 (lowest) to * 0 (highest) in steps of 1.5dB. Levels between increments of 1.5 will be rounded down. * * \return 0 on success, or nonzero if an error occurred. */ +int Bela_setAdcLevel(int channel, float decibels); + +/** + * DEPRECATED. + * + * Equivalent to `Bela_setAdcLevel(-1, decibels)`. + */ int Bela_setADCLevel(float decibels); /** - * \brief Set the gain of the audio preamplifier. + * \brief Set the gain of the audio input preamplifier. * * This function sets the level of the Programmable Gain Amplifier(PGA), which * amplifies the signal before the ADC. @@ -862,13 +902,20 @@ int Bela_setADCLevel(float decibels); * \b Important: do not call this function from within render(), as it does not make * any guarantees on real-time performance. * + * \param channel The channel to set. Use a negative value to set all channels. * \param decibels Level of the PGA Valid levels range from 0 (lowest) to * 59.5 (highest) in steps of 0.5dB. Levels between increments of 0.5 will be rounded. - * \param channel Specifies which channel to apply the gain to. Channel 0 is left, * channel 1 is right * * \return 0 on success, or nonzero if an error occurred. */ +int Bela_setAudioInputGain(int channel, float decibels); + +/** + * DEPRECATED. + * + * Equivalent to `Bela_setAudioInputGain(channel, decibels)`. + */ int Bela_setPgaGain(float decibels, int channel); /** @@ -881,11 +928,17 @@ int Bela_setPgaGain(float decibels, int channel); * \b Important: do not call this function from within render(), as it does not make * any guarantees on real-time performance. * - * \param decibels Level of the DAC output. Valid levels range from -63.5 (lowest) to + * \param channel The channel to set. Use a negative value to set all channels. + * \param decibels Level of the headphone output. Valid levels range from -63.5 (lowest) to * 0 (highest) in steps of 0.5dB. Levels between increments of 0.5 will be rounded down. * * \return 0 on success, or nonzero if an error occurred. */ +int Bela_setHpLevel(int channel, float decibels); +/** + * DEPRECATED + * Equivalent to Bela_setHpLevel(-1, decibels); + */ int Bela_setHeadphoneLevel(float decibels); /** diff --git a/include/I2c_Codec.h b/include/I2c_Codec.h index 915b393c0..27e7556e6 100644 --- a/include/I2c_Codec.h +++ b/include/I2c_Codec.h @@ -16,6 +16,7 @@ #include "AudioCodec.h" #include "I2c.h" +#include class I2c_Codec : public I2c, public AudioCodec { @@ -54,13 +55,10 @@ class I2c_Codec : public I2c, public AudioCodec unsigned int getPllR(); float getPllK(); float getAudioSamplingRate(); - int setPga(float newGain, unsigned short int channel); - int setDACVolume(int halfDbSteps); - int writeDACVolumeRegisters(bool mute); - int setADCVolume(int halfDbSteps); - int writeADCVolumeRegisters(bool mute); - int setHPVolume(int halfDbSteps); - int writeHPVolumeRegisters(); + int setInputGain(int channel, float gain); + int setDacVolume(int channel, float gain); + int setAdcVolume(int channel, float gain); + int setHpVolume(int channel, float gain); int enableHpOut(bool enable); int enableLineOut(bool enable); int disable(); @@ -74,12 +72,17 @@ class I2c_Codec : public I2c, public AudioCodec virtual McaspConfig& getMcaspConfig(); int setMode(std::string str); +private: + enum {kNumIoChannels = 2}; + int writeDacVolumeRegisters(bool mute); + int writeAdcVolumeRegisters(bool mute); + int writeHPVolumeRegisters(); protected: int configureDCRemovalIIR(bool enable); //called by startAudio() int codecType; - int dacVolumeHalfDbs; - int adcVolumeHalfDbs; - int hpVolumeHalfDbs; + std::array dacVolumeHalfDbs{}; + std::array adcVolumeHalfDbs{}; + std::array hpVolumeHalfDbs{}; AudioCodecParams params; McaspConfig mcaspConfig; bool running; diff --git a/include/I2c_MultiTLVCodec.h b/include/I2c_MultiTLVCodec.h index 782c8759e..2b3e8070f 100644 --- a/include/I2c_MultiTLVCodec.h +++ b/include/I2c_MultiTLVCodec.h @@ -33,10 +33,10 @@ class I2c_MultiTLVCodec : public AudioCodec unsigned int getNumOuts(); float getSampleRate(); - int setPga(float newGain, unsigned short int channel); - int setDACVolume(int halfDbSteps); - int setADCVolume(int halfDbSteps); - int setHPVolume(int halfDbSteps); + int setInputGain(int channel, float newGain); + int setDacVolume(int channel, float gain); + int setAdcVolume(int channel, float gain); + int setHpVolume(int channel, float gain); int disable(); int reset(); int setMode(std::string parameter); diff --git a/include/Spi_Codec.h b/include/Spi_Codec.h index 0d2ce7400..fc9fe8a6a 100644 --- a/include/Spi_Codec.h +++ b/include/Spi_Codec.h @@ -50,20 +50,20 @@ class Spi_Codec : public AudioCodec { unsigned int getNumIns(); unsigned int getNumOuts(); float getSampleRate(); - int setDACVolume(int halfDbSteps); int dumpRegisters(); int reset(); // Hard reset of codec(s) bool masterIsDetected(); // CTAG face2|4 bool slaveIsDetected(); // CTAG Beast - int setADCVolume(int halfDbSteps) {return 0;}; - int setHPVolume(int halfDbSteps) {return 0;}; - int setPga(float newGain, unsigned short int channel) {return 0;}; + int setDacVolume(int channel, float gain); + int setAdcVolume(int channel, float gain) { return 0; }; + int setHpVolume(int channel, float gain) { return 0; }; + int setInputGain(int channel, float newGain) { return 0; }; int disable() {return 0;}; McaspConfig& getMcaspConfig(); private: int _fd_master, _fd_slave; - int _dacVolumethreeEighthsDbs; + std::vector _dacVolumethreeEighthsDbs; int _writeDACVolumeRegisters(bool mute); int _spiTransfer(unsigned char* tx_buf, unsigned char* rx_buf, size_t bytes, CODEC_TYPE codec = MASTER_CODEC); McaspConfig mcaspConfig; From 1d70234d4cde785371e7f253a01376979d6fde41 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 2 Jul 2021 14:23:06 +0000 Subject: [PATCH 123/148] Reverting pru_rtaudio.p to the `dev` branch, with minimal changes to make it build --- pru/pru_rtaudio.p | 103 +++++----------------------------------------- 1 file changed, 10 insertions(+), 93 deletions(-) diff --git a/pru/pru_rtaudio.p b/pru/pru_rtaudio.p index ebed8ef71..e11ff74ae 100644 --- a/pru/pru_rtaudio.p +++ b/pru/pru_rtaudio.p @@ -173,56 +173,8 @@ #define MCASP_OUTPUT_PINS (1 << 3) // Which pins are outputs #endif -#define MCASP_SLOT_16BITS - -#ifdef MCASP_SLOT_16BITS #define MCASP_DATA_MASK 0xFFFF // 16 bit data -#endif - -#ifdef MCASP_SLOT_20BITS -#define MCASP_DATA_MASK 0xFFFFF // 20 bit data -#endif - -#ifdef MCASP_SLOT_24BITS -#define MCASP_DATA_MASK 0xFFFFFF // 24 bit data -#endif - -#ifdef MCASP_SLOT_32BITS -#define MCASP_DATA_MASK 0xFFFFFFFF // 32 bit data -#endif - -#define TLV320_MODE_DSP - -#ifdef TLV320_MODE_I2S -#define MCASP_AFSCTL_VALUE 0x101 // 2-slot TDM I2S mode, falling edge means beginning of frame -#define MCASP_DATA_FORMAT_VALUE 0x1807C // MSB first, 1 bit delay, 16 bits, CFG bus, ROR 16bits -#define MCASP_ACLKXCTL_VALUE 0x80 // Transmit on rising edge, sync. xmit and recv -#endif - -#ifdef TLV320_MODE_DSP -#define MCASP_AFSCTL_VALUE 0x100 // 2-slot TDM I2S mode, rising edge means beginning of frame -#define MCASP_ACLKXCTL_VALUE 0x00 // Transmit on falling edge, sync. xmit and recv -#define MCASP_DATA_FORMAT_VALUE 0x807C // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits -#endif - -#ifdef TLV320_MODE_TDM - -#ifdef MCASP_SLOT_16BITS -#define MCASP_AFSCTL_VALUE 0x800 // 16-slot TDM, rising edge means beginning of frame -#define MCASP_DATA_FORMAT_VALUE 0x807C // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits -#endif // MCASP_SLOT_16BITS - -#ifdef MCASP_SLOT_32BITS -#define MCASP_AFSCTL_VALUE 0x400 // 8-slot TDM, rising edge means beginning of frame -#define MCASP_DATA_FORMAT_VALUE 0x80F8 // MSB first, 0 bit delay, 32 bits, CFG bus, ROR 0bits -#endif // MCASP_SLOT_32BITS - -// 20 and 24 bit slots not supported in 256-cycle TDM -// Hypothetically, for 20 bits, MCASP_DATA_FORMAT_VALUE = 0x809B -// Hypothetically, for 24 bits, MCASP_DATA_FORMAT_VALUE = 0x80BA - -#define MCASP_ACLKXCTL_VALUE 0x00 // Transmit on falling edge, sync. xmit and recv -#endif // TLV320_MODE_TDM +#define MCASP_DATA_FORMAT 0x807C // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits #define C_MCASP_MEM C28 // Shared PRU mem @@ -931,27 +883,18 @@ SPI_INIT_DONE: MCASP_REG_WRITE MCASP_DLBCTL, 0x00 MCASP_REG_WRITE MCASP_DITCTL, 0x00 MCASP_REG_WRITE MCASP_RMASK, MCASP_DATA_MASK // 16 bit data receive - MCASP_REG_WRITE MCASP_RFMT, MCASP_DATA_FORMAT_VALUE // Set data format - MCASP_REG_WRITE MCASP_AFSRCTL, MCASP_AFSCTL_VALUE + MCASP_REG_WRITE MCASP_RFMT, MCASP_DATA_FORMAT // Set data format + MCASP_REG_WRITE MCASP_AFSRCTL, 0x100 // I2S mode MCASP_REG_WRITE MCASP_ACLKRCTL, 0x80 // Sample on rising edge MCASP_REG_WRITE MCASP_AHCLKRCTL, 0x8001 // Internal clock, not inv, /2; irrelevant? - - // Calculate which TDM slots to activate - LBBO r2, reg_comm_addr, COMM_ACTIVE_CHANNELS, 4 // How many audio channels? - MOV r3, 0x1 // mask = (1 << numchannels) - 1 - LSL r3, r3, r2 - SUB r3, r3, 1 - OR r3, r3, 0x03 // Always activate the first two slots (failsafe) - AND r3, r3, 0x1F // Never more than 32 slots - - MCASP_REG_WRITE MCASP_RTDM, r3 // Set enabled TDM slots + MCASP_REG_WRITE MCASP_RTDM, 0x03 // Enable TDM slots 0 and 1 MCASP_REG_WRITE MCASP_RINTCTL, 0x00 // No interrupts MCASP_REG_WRITE MCASP_XMASK, MCASP_DATA_MASK // 16 bit data transmit - MCASP_REG_WRITE MCASP_XFMT, MCASP_DATA_FORMAT_VALUE // Set data format - MCASP_REG_WRITE MCASP_AFSXCTL, MCASP_AFSCTL_VALUE - MCASP_REG_WRITE MCASP_ACLKXCTL, MCASP_ACLKXCTL_VALUE + MCASP_REG_WRITE MCASP_XFMT, MCASP_DATA_FORMAT // Set data format + MCASP_REG_WRITE MCASP_AFSXCTL, 0x100 // I2S mode + MCASP_REG_WRITE MCASP_ACLKXCTL, 0x00 // Transmit on rising edge, sync. xmit and recv MCASP_REG_WRITE MCASP_AHCLKXCTL, 0x8001 // External clock from AHCLKX - MCASP_REG_WRITE MCASP_XTDM, r3 // Set enabled TDM slots + MCASP_REG_WRITE MCASP_XTDM, 0x03 // Enable TDM slots 0 and 1 MCASP_REG_WRITE MCASP_XINTCTL, 0x00 // No interrupts MCASP_REG_WRITE_EXT MCASP_SRCTL_R, 0x02 // Set up receive serialiser @@ -1047,11 +990,6 @@ MCASP_ADC_WAIT_BEFORE_LOOP: QBBC MCASP_ADC_WAIT_BEFORE_LOOP, r2, MCASP_RSTAT_RDATA_BIT MCASP_REG_READ_EXT MCASP_RBUF, r2 - -// TODO: may need to wait a full cycle in TDM mode >2 channels; see XSLOT register -// ...but which slot do we wait for, and how do we know to skip inactive slots? -// LBBO r2, reg_mcasp_addr, MCASP_XSLOT, 4 -// QBNE MCASP_DAC_WAIT_BEFORE_LOOP, r2, 0 WRITE_ONE_BUFFER: @@ -1109,22 +1047,11 @@ MCASP_DAC_LOW_WORD: // Mask out the low word (first in little endian) MOV r2, 0xFFFF AND r7, reg_mcasp_dac_data, r2 - -#ifdef MCASP_SLOT_32BITS - LSL r7, r7, 16 // Convert 16-bit number to 32-bit -#endif QBA MCASP_WAIT_XSTAT MCASP_DAC_HIGH_WORD: // Take the high word of the previously loaded data -#ifdef MCASP_SLOT_16BITS - LSR r7, reg_mcasp_dac_data, 16 // Move high word to low 16 bits -#endif - -#ifdef MCASP_SLOT_32BITS - MOV r2, 0xFFFF0000 - AND r7, reg_mcasp_dac_data, r2 // Mask out low 16 bits -#endif + LSR r7, reg_mcasp_dac_data, 16 // Every 2 channels we send one audio sample; this loop already // sends exactly two SPI channels. @@ -1151,9 +1078,6 @@ MCASP_WAIT_RSTAT_LOW: // Mask low word and store in ADC data register MCASP_REG_READ_EXT MCASP_RBUF, r3 -#ifdef MCASP_SLOT_32BITS - LSR r3, r3, 16 // 32-bit value to 16-bit -#endif MOV r2, 0xFFFF AND reg_mcasp_adc_data, r3, r2 QBA MCASP_ADC_DONE @@ -1166,14 +1090,7 @@ MCASP_WAIT_RSTAT_HIGH: // Read data and shift 16 bits to the left (into the high word) MCASP_REG_READ_EXT MCASP_RBUF, r3 -#ifdef MCASP_SLOT_16BITS - LSL r3, r3, 16 // 16-bit value to high part of word -#endif - -#ifdef MCASP_SLOT_32BITS - MOV r2, 0xFFFF0000 // Mask out low 16 bits of 32-bit word - AND r3, r3, r2 -#endif + LSL r3, r3, 16 OR reg_mcasp_adc_data, reg_mcasp_adc_data, r3 // Now store the result and increment the pointer From 0ce65fbca3e09c5fe48fdfbde7bde056cc2eb42b Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 2 Jul 2021 16:13:17 +0000 Subject: [PATCH 124/148] pru/pru_rtaudio.p: works again (or as much as it works on dev: at 2 analog channels audio is corrupted) --- core/PRU.cpp | 5 ++++- pru/pru_rtaudio.p | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/core/PRU.cpp b/core/PRU.cpp index 4e35f1356..64077571a 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -594,7 +594,10 @@ void PRU::initialisePruCommon(const McaspRegisters& mcaspRegisters) else pruFrames = context->audioFrames / 2; // PRU assumes 8 "fake" channels when SPI is disabled pru_buffer_comm[PRU_COMM_BUFFER_SPI_FRAMES] = pruFrames; - pruBufferMcaspFrames = context->audioFrames; + if(pruUsesMcaspIrq) + pruBufferMcaspFrames = context->audioFrames; + else // TODO: it seems that PRU_COMM_BUFFER_MCASP_FRAMES is not very meaningful(cf pru_rtaudio_irq.p) + pruBufferMcaspFrames = pruFrames * context->audioOutChannels / 2; pru_buffer_comm[PRU_COMM_BUFFER_MCASP_FRAMES] = pruBufferMcaspFrames; pru_buffer_comm[PRU_COMM_SHOULD_SYNC] = 0; pru_buffer_comm[PRU_COMM_SYNC_ADDRESS] = 0; diff --git a/pru/pru_rtaudio.p b/pru/pru_rtaudio.p index e11ff74ae..ac296d026 100644 --- a/pru/pru_rtaudio.p +++ b/pru/pru_rtaudio.p @@ -886,14 +886,14 @@ SPI_INIT_DONE: MCASP_REG_WRITE MCASP_RFMT, MCASP_DATA_FORMAT // Set data format MCASP_REG_WRITE MCASP_AFSRCTL, 0x100 // I2S mode MCASP_REG_WRITE MCASP_ACLKRCTL, 0x80 // Sample on rising edge - MCASP_REG_WRITE MCASP_AHCLKRCTL, 0x8001 // Internal clock, not inv, /2; irrelevant? + MCASP_REG_WRITE MCASP_AHCLKRCTL, 0x8000 // Internal clock, not inv, /1; irrelevant? MCASP_REG_WRITE MCASP_RTDM, 0x03 // Enable TDM slots 0 and 1 MCASP_REG_WRITE MCASP_RINTCTL, 0x00 // No interrupts MCASP_REG_WRITE MCASP_XMASK, MCASP_DATA_MASK // 16 bit data transmit MCASP_REG_WRITE MCASP_XFMT, MCASP_DATA_FORMAT // Set data format MCASP_REG_WRITE MCASP_AFSXCTL, 0x100 // I2S mode MCASP_REG_WRITE MCASP_ACLKXCTL, 0x00 // Transmit on rising edge, sync. xmit and recv - MCASP_REG_WRITE MCASP_AHCLKXCTL, 0x8001 // External clock from AHCLKX + MCASP_REG_WRITE MCASP_AHCLKXCTL, 0x8000 // External clock from AHCLKX MCASP_REG_WRITE MCASP_XTDM, 0x03 // Enable TDM slots 0 and 1 MCASP_REG_WRITE MCASP_XINTCTL, 0x00 // No interrupts From 4d344fb200b92fb24e3876dad8e1fb154bd462e3 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 30 Jul 2021 17:52:42 +0000 Subject: [PATCH 125/148] Removed compiler warnings (g++-8.3.0) --- Makefile | 2 ++ core/BelaContextSplitter.cpp | 2 +- core/DataFifo.cpp | 6 +++--- core/I2c_Codec.cpp | 11 +++++++---- core/I2c_MultiTLVCodec.cpp | 4 ++-- core/MiscUtilities.cpp | 3 ++- core/PRU.cpp | 19 ++++++++----------- core/RTAudio.cpp | 2 +- core/Spi_Codec.cpp | 4 ++-- core/WSServer.cpp | 6 +++--- core/board_detect.cpp | 3 ++- include/bela_sw_settings.h | 4 ++-- libraries/Biquad/Biquad.cpp | 5 +++-- 13 files changed, 38 insertions(+), 33 deletions(-) diff --git a/Makefile b/Makefile index 2ac97098d..7210373ef 100644 --- a/Makefile +++ b/Makefile @@ -347,6 +347,8 @@ else ifeq ($(COMPILER), gcc) CC=gcc CXX=g++ + DEFAULT_CPPFLAGS += -Wno-psabi + DEFAULT_CFLAGS += -Wno-psabi LDFLAGS+=-fno-pie -no-pie endif endif diff --git a/core/BelaContextSplitter.cpp b/core/BelaContextSplitter.cpp index 401dd9434..7faae1f4b 100644 --- a/core/BelaContextSplitter.cpp +++ b/core/BelaContextSplitter.cpp @@ -297,7 +297,7 @@ bool BelaContextSplitter::test() // test the actual class BelaContextSplitter spl1; BelaContextSplitter spl2; - int factor = 4; + unsigned int factor = 4; spl1.setup(factor, 1, (BelaContext*)&ctx1); ctx2 = ctx1; ctx2.audioFrames *= factor; diff --git a/core/DataFifo.cpp b/core/DataFifo.cpp index 0b8a6c70d..85b67f3b8 100644 --- a/core/DataFifo.cpp +++ b/core/DataFifo.cpp @@ -124,8 +124,8 @@ void fillArray(std::vector& vec) bool DataFifo::test() { DataFifo df; - size_t msgSize = 1000; - size_t numMsg = 100; + ssize_t msgSize = 1000; + ssize_t numMsg = 100; std::vector sent(msgSize * numMsg); std::vector received(msgSize * numMsg); for(unsigned int n = 0; n < sent.size(); ++n) @@ -146,7 +146,7 @@ bool DataFifo::test() ret = df.send(sent.data(), msgSize * 2); assert(-EMSGSIZE == ret); - size_t newsz = msgSize / 2; + ssize_t newsz = msgSize / 2; ret = df.send(sent.data(), newsz); assert(0 == ret); fillArray(received); diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index ab5cf68e6..5e9b87d45 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -15,6 +15,7 @@ #include "../include/I2c_Codec.h" #include #include +#include // if only we could be `using` these... constexpr AudioCodecParams::TdmMode kTdmModeI2s = AudioCodecParams::kTdmModeI2s; @@ -460,8 +461,8 @@ struct PllSettings { double Fs; }; -std::vector findSettingsWithConstraints( - int Rmin, int Rmax, +static std::vector findSettingsWithConstraints( + unsigned int Rmin, unsigned int Rmax, double Kmin, double Kmax, double ratioMin, double ratioMax, bool integerK, double PLLCLK_IN, @@ -558,7 +559,7 @@ int I2c_Codec::setAudioSamplingRate(float newSamplingRate){ return 1; } // find the settings that minimise the Fs error - PllSettings optimalSettings; + PllSettings optimalSettings = {0}; double error = std::numeric_limits::max(); for(auto & s : settings) { double newError = std::abs(s.Fs - newSamplingRate); @@ -642,7 +643,7 @@ static int setByChannel(T& dest, const int channel, U val) return 1; for(unsigned int n = 0; n < dest.size(); ++n) { - if(channel == n || channel < 0) + if(channel == int(n) || channel < 0) { dest[n] = val; if(channel >= 0) @@ -968,6 +969,8 @@ McaspConfig& I2c_Codec::getMcaspConfig() // codec is in 256-bit mode numSlots = 256 / params.slotSize; break; + default: + throw std::runtime_error("I2c_Codec: invalid TdmMode"); } bool isI2s = (kTdmModeI2s == params.tdmMode); mcaspConfig.params.inChannels = getNumIns(); diff --git a/core/I2c_MultiTLVCodec.cpp b/core/I2c_MultiTLVCodec.cpp index 876a16fac..61811fd7f 100644 --- a/core/I2c_MultiTLVCodec.cpp +++ b/core/I2c_MultiTLVCodec.cpp @@ -38,7 +38,7 @@ static I2c_Codec::CodecType getCodecTypeFromString(const std::string& str) { try { return codecTypeMap.at(trim(str)); - } catch(std::exception e) { + } catch(std::exception&) { throwErr("Unrecognised codec type", str); } } @@ -210,7 +210,7 @@ int I2c_MultiTLVCodec::stopAudio() ret |= c->do;\ return ret;\ }\ - int cod = channel / 2;\ + unsigned int cod = channel / 2;\ channel = channel % 2;\ if(cod >= codecs.size())\ return -1;\ diff --git a/core/MiscUtilities.cpp b/core/MiscUtilities.cpp index 5c5259f93..c7e1b13de 100644 --- a/core/MiscUtilities.cpp +++ b/core/MiscUtilities.cpp @@ -57,6 +57,7 @@ std::ofstream openOutput(const std::string& path, Mode mode) openmode = std::ios_base::app; break; case TRUNCATE: + default: openmode = std::ios_base::trunc; break; } @@ -86,7 +87,7 @@ std::string readTextFile(const std::string& path) in.exceptions(std::fstream::failbit | std::fstream::badbit); in.open(path); } - catch (std::exception e) + catch (std::exception&) { return ""; } diff --git a/core/PRU.cpp b/core/PRU.cpp index 64077571a..b67729490 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -124,17 +124,17 @@ class PruMemory // Clear / initialize memory for(int buffer = 0; buffer < 2; ++buffer) { - for(int i = 0; i < analogOut.size(); i++) + for(unsigned int i = 0; i < analogOut.size(); i++) pruAnalogOutStart[buffer][i] = 0; - for(int i = 0; i < analogIn.size(); i++) + for(unsigned int i = 0; i < analogIn.size(); i++) pruAnalogInStart[buffer][i] = 0; - for(int i = 0; i < audioOut.size(); i++) + for(unsigned int i = 0; i < audioOut.size(); i++) pruAudioOutStart[buffer][i] = 0; - for(int i = 0; i < audioIn.size(); i++) + for(unsigned int i = 0; i < audioIn.size(); i++) pruAudioInStart[buffer][i] = 0; // set digital to all inputs, to avoid unexpected spikes uint32_t* digitalUint32View = (uint32_t*)pruDigitalStart[buffer]; - for(int i = 0; i < digital.size(); i++) + for(unsigned int i = 0; i < digital.size(); i++) { digitalUint32View[i] = 0x0000ffff; } @@ -899,7 +899,6 @@ void PRU::loop(void *userData, void(*render)(BelaContext*, void*), bool highPerf int underrunLedCount = -1; while(!Bela_stopRequested()) { - int error = 0; #if defined BELA_USE_POLL || defined BELA_USE_BUSYWAIT // Which buffer the PRU was last processing static uint32_t lastPRUBuffer = 0; @@ -908,10 +907,8 @@ void PRU::loop(void *userData, void(*render)(BelaContext*, void*), bool highPerf #ifdef BELA_USE_POLL task_sleep_ns(sleepTime); #endif /* BELA_USE_POLL */ - if(error = testPruError()) - { + if(testPruError()) break; - } } lastPRUBuffer = pru_buffer_comm[PRU_COMM_CURRENT_BUFFER]; @@ -921,7 +918,7 @@ void PRU::loop(void *userData, void(*render)(BelaContext*, void*), bool highPerf if(!highPerformanceMode) // unless the user requested us not to. task_sleep_ns(sleepTime / 2); int ret = __wrap_read(rtdm_fd_pru_to_arm, NULL, 0); - error = testPruError(); + int error = testPruError(); if(2 == error) { gShouldStop = true; break; @@ -966,7 +963,7 @@ void PRU::loop(void *userData, void(*render)(BelaContext*, void*), bool highPerf int16_to_float_audio(2 * context->audioFrames, audio_adc_pru_buffer, context->audioIn); // TODO: implement non-interlaved #else - int audioInChannels = context->audioInChannels; + unsigned int audioInChannels = context->audioInChannels; if(interleaved) { for(unsigned int n = 0; n < audioInChannels * context->audioFrames; n++) { diff --git a/core/RTAudio.cpp b/core/RTAudio.cpp index 321ede30f..a0bad69fe 100644 --- a/core/RTAudio.cpp +++ b/core/RTAudio.cpp @@ -558,7 +558,7 @@ int Bela_initAudio(BelaInitSettings *settings, void *userData) if(settings->projectName) { - strncpy(gContext.projectName, settings->projectName, MAX_PROJECTNAME_LENGTH); + strncpy(gContext.projectName, settings->projectName, MAX_PROJECTNAME_LENGTH - 1); if(gRTAudioVerbose) printf("Project name: %s\n", gContext.projectName); } diff --git a/core/Spi_Codec.cpp b/core/Spi_Codec.cpp index 6afa20f60..dc19e9070 100644 --- a/core/Spi_Codec.cpp +++ b/core/Spi_Codec.cpp @@ -197,7 +197,7 @@ int Spi_Codec::setDacVolume(const int channel, float gain) { // Calculcate volume from gain dB in 3/8 dB steps und cast to int for(unsigned int n = 0; n < _dacVolumethreeEighthsDbs.size(); ++n) { - if(channel < 0 || channel == n) + if(channel < 0 || channel == int(n)) _dacVolumethreeEighthsDbs[n] = (int) ((float) (gain * 2) * (1.0 + 1.0/3.0)); } @@ -286,7 +286,7 @@ int Spi_Codec::_writeDACVolumeRegisters(bool mute){ MASTER_CODEC, SLAVE_CODEC, }}; - for(unsigned int c = 0; c < _isBeast + 1; ++c) + for(int c = 0; c < _isBeast + 1; ++c) { for(unsigned int n = 0; n < volumeBits.size() && n < regsDacVolume.size(); ++n) { diff --git a/core/WSServer.cpp b/core/WSServer.cpp index d0757cccb..61eb0d090 100644 --- a/core/WSServer.cpp +++ b/core/WSServer.cpp @@ -97,7 +97,7 @@ int WSServer::sendNonRt(const char* _address, const void* buf, unsigned int size try { client_task_func(address_book.at(_address).handler, buf, size); return 0; - } catch (std::exception) { + } catch (std::exception&) { return -1; } } @@ -105,7 +105,7 @@ int WSServer::sendNonRt(const char* _address, const void* buf, unsigned int size int WSServer::sendRt(const char* _address, const char* str){ try { return address_book.at(_address).thread->schedule(str); - } catch (std::exception) { + } catch (std::exception&) { return -1; } } @@ -113,7 +113,7 @@ int WSServer::sendRt(const char* _address, const char* str){ int WSServer::sendRt(const char* _address, const void* buf, unsigned int size){ try { return address_book.at(_address).thread->schedule(buf, size); - } catch (std::exception) { + } catch (std::exception&) { return -1; } } diff --git a/core/board_detect.cpp b/core/board_detect.cpp index 3885b88cd..458affb78 100644 --- a/core/board_detect.cpp +++ b/core/board_detect.cpp @@ -91,7 +91,7 @@ BelaHw getBelaHw(std::string board) { try { return belaHwMap.at(board); - } catch (std::exception e) { + } catch (std::exception& e) { return BelaHw_NoHw; } } @@ -267,4 +267,5 @@ unsigned int Bela_hwContains(const BelaHw hw, const BelaHwComponent::Component c return Bela_hwContains(hw, BelaCape) || Bela_hwContains(hw, BelaMiniCape); break; } + return 0; } diff --git a/include/bela_sw_settings.h b/include/bela_sw_settings.h index ccb875d7a..f8b304bf5 100644 --- a/include/bela_sw_settings.h +++ b/include/bela_sw_settings.h @@ -1,4 +1,4 @@ #pragma once -static const char* sysBelaConfig = "/run/bela/belaconfig"; -static const char* userBelaConfig = "/root/.bela/belaconfig"; +static const char* const sysBelaConfig = "/run/bela/belaconfig"; +static const char* const userBelaConfig = "/root/.bela/belaconfig"; diff --git a/libraries/Biquad/Biquad.cpp b/libraries/Biquad/Biquad.cpp index d6df30d7c..f895b625e 100644 --- a/libraries/Biquad/Biquad.cpp +++ b/libraries/Biquad/Biquad.cpp @@ -118,14 +118,15 @@ void BiquadCoeffT::calc() return; } +#include int QuadBiquad::setup(const BiquadCoeff::Settings& settings) { int ret = 0; for(auto & b : filters) ret |= b.setup(settings); update(); - z1 = {0}; - z2 = {0}; + memset(&z1, 0, sizeof(z1)); + memset(&z2, 0, sizeof(z2)); return ret; } void QuadBiquad::update() From 459cde0f2a5c0ab5a689e2bbbc1e919d12e5fb10 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Thu, 29 Jul 2021 23:36:18 +0000 Subject: [PATCH 126/148] pru: NIT: factored out CLOCK_MCASP_VALUE --- pru/pru_rtaudio.p | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pru/pru_rtaudio.p b/pru/pru_rtaudio.p index ac296d026..cc836d2b0 100644 --- a/pru/pru_rtaudio.p +++ b/pru/pru_rtaudio.p @@ -7,6 +7,7 @@ #define CLOCK_BASE 0x44E00000 #define CLOCK_MCASP0 0x34 +#define CLOCK_MCASP_VALUE 0x30002 // should probably be just 0x2 #define CLOCK_SPI0 0x4C #define CLOCK_SPI1 0x50 #define CLOCK_L4LS 0x60 @@ -864,7 +865,7 @@ SPI_WAIT_RESET: SPI_INIT_DONE: // enable MCASP interface clock in PRCM - MOV r2, 0x30002 + MOV r2, CLOCK_MCASP_VALUE MOV r3, CLOCK_BASE + CLOCK_MCASP0 SBBO r2, r3, 0, 4 From 4c3350711fc5230d9b2ac5af8cc81d02d4bd4eb5 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Thu, 29 Jul 2021 23:40:59 +0000 Subject: [PATCH 127/148] pru: wait for a few cycles after enabling McASP module clock in order to ensure proper initialisation --- pru/pru_rtaudio.p | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pru/pru_rtaudio.p b/pru/pru_rtaudio.p index cc836d2b0..c8a2222fe 100644 --- a/pru/pru_rtaudio.p +++ b/pru/pru_rtaudio.p @@ -869,6 +869,14 @@ SPI_INIT_DONE: MOV r3, CLOCK_BASE + CLOCK_MCASP0 SBBO r2, r3, 0, 4 + // we need to wait for a few cycles after enabling the clock in order for + // the McASP to work properly (we found experimentally that this is + // required for some SoCs (e.g.: AM572x)) + MOV r2, 1000 +MCASP_CLOCK_ENABLE_LOOP: + SUB r2, r2, 1 + QBNE MCASP_CLOCK_ENABLE_LOOP, r2, 0 + // Prepare McASP0 for audio MCASP_REG_WRITE MCASP_GBLCTL, 0 // Disable McASP MCASP_REG_WRITE_EXT MCASP_SRCTL0, 0 // All serialisers off From cc287757699b721e35fbefd52e84bb296b98ea3f Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Thu, 29 Jul 2021 21:01:07 +0000 Subject: [PATCH 128/148] Makefile: BELA_USE_DEFINE is now ?= so it can be overridden more easily in CustomMakefileTop.in --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 7210373ef..cad3c9c6b 100644 --- a/Makefile +++ b/Makefile @@ -288,10 +288,10 @@ LEGACY_INCLUDE_PATH := ./include/legacy INCLUDES := -I$(PROJECT_DIR) -I$(LEGACY_INCLUDE_PATH) -I./include -I./build/pru/ -I./ ifeq ($(XENOMAI_VERSION),2.6) - BELA_USE_DEFINE=BELA_USE_POLL + BELA_USE_DEFINE?=BELA_USE_POLL endif ifeq ($(XENOMAI_VERSION),3) - BELA_USE_DEFINE=BELA_USE_RTDM + BELA_USE_DEFINE?=BELA_USE_RTDM endif DEFAULT_COMMON_FLAGS := $(DEFAULT_XENOMAI_CFLAGS) -O3 -g -march=armv7-a -mtune=cortex-a8 -mfloat-abi=hard -mfpu=neon -ftree-vectorize -ffast-math -DNDEBUG -D$(BELA_USE_DEFINE) -I$(BASE_DIR)/resources/$(DEBIAN_VERSION)/include -save-temps=obj From c31b7a10e17b497c1607f99da69666ff8e4dda3d Mon Sep 17 00:00:00 2001 From: Dhruva_Gole Date: Sun, 4 Jul 2021 20:22:18 +0530 Subject: [PATCH 129/148] PruManager: factored libprussdrv out of PRU into PruManager. No functional change. Co-authored-by: Giulio Moro --- Makefile | 2 +- core/PRU.cpp | 74 ++++++++++++---------------------- core/PruManager.cpp | 95 ++++++++++++++++++++++++++++++++++++++++++++ include/PRU.h | 2 + include/PruManager.h | 45 +++++++++++++++++++++ 5 files changed, 169 insertions(+), 49 deletions(-) create mode 100644 core/PruManager.cpp create mode 100644 include/PruManager.h diff --git a/Makefile b/Makefile index cad3c9c6b..93c7351be 100644 --- a/Makefile +++ b/Makefile @@ -395,7 +395,7 @@ ALL_DEPS += $(addprefix build/core/,$(notdir $(CORE_C_SRCS:.c=.d))) CORE_CPP_SRCS = $(filter-out core/default_main.cpp core/default_libpd_render.cpp, $(wildcard core/*.cpp)) CORE_OBJS := $(CORE_OBJS) $(addprefix build/core/,$(notdir $(CORE_CPP_SRCS:.cpp=.o))) -CORE_CORE_OBJS := build/core/RTAudio.o build/core/PRU.o build/core/RTAudioCommandLine.o build/core/I2c_Codec.o build/core/I2c_MultiTLVCodec.o build/core/I2c_MultiTdmCodec.o build/core/Spi_Codec.o build/core/math_runfast.o build/core/GPIOcontrol.o build/core/PruBinary.o build/core/board_detect.o build/core/DataFifo.o build/core/BelaContextFifo.o build/core/BelaContextSplitter.o build/core/MiscUtilities.o build/core/Mmap.o build/core/Mcasp.o +CORE_CORE_OBJS := build/core/RTAudio.o build/core/PRU.o build/core/RTAudioCommandLine.o build/core/I2c_Codec.o build/core/I2c_MultiTLVCodec.o build/core/I2c_MultiTdmCodec.o build/core/Spi_Codec.o build/core/math_runfast.o build/core/GPIOcontrol.o build/core/PruBinary.o build/core/board_detect.o build/core/DataFifo.o build/core/BelaContextFifo.o build/core/BelaContextSplitter.o build/core/MiscUtilities.o build/core/Mmap.o build/core/Mcasp.o build/core/PruManager.o EXTRA_CORE_OBJS := $(filter-out $(CORE_CORE_OBJS), $(CORE_OBJS)) ALL_DEPS += $(addprefix build/core/,$(notdir $(CORE_CPP_SRCS:.cpp=.d))) diff --git a/core/PRU.cpp b/core/PRU.cpp index b67729490..44f580c6a 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -14,8 +14,7 @@ */ #include "../include/PRU.h" -#include "../include/PruBinary.h" -#include + #include "../include/digital_gpio_mapping.h" #include "../include/GPIOcontrol.h" #include "../include/Bela.h" @@ -97,10 +96,10 @@ extern int gRTAudioVerbose; class PruMemory { public: - PruMemory(int pruNumber, InternalBelaContext* newContext) : + PruMemory(int pruNumber, InternalBelaContext* newContext, PruManager& pruManager) : context(newContext) { - prussdrv_map_prumem (PRUSS0_SHARED_DATARAM, (void **)&pruSharedRam); + pruSharedRam = static_cast(pruManager.getSharedMemory()); audioIn.resize(context->audioInChannels * context->audioFrames); audioOut.resize(context->audioOutChannels * context->audioFrames); digital.resize(context->digitalFrames); @@ -112,7 +111,7 @@ class PruMemory pruDigitalStart[1] = pruSharedRam + PRU_MEM_DIGITAL_OFFSET + PRU_MEM_DIGITAL_BUFFER1_OFFSET; if(context->analogFrames > 0) { - prussdrv_map_prumem (pruNumber == 0 ? PRUSS0_PRU0_DATARAM : PRUSS0_PRU1_DATARAM, (void**)&pruDataRam); + pruDataRam = static_cast(pruManager.getOwnMemory()); analogOut.resize(context->analogOutChannels * context->analogFrames); analogIn.resize(context->analogInChannels * context->analogFrames); pruAnalogOutStart[0] = pruDataRam + PRU_MEM_DAC_OFFSET; @@ -384,12 +383,8 @@ int PRU::initialise(BelaHw newBelaHw, int pru_num, bool uniformSampleRate, int m pru_number = pru_num; /* Allocate and initialize memory */ - prussdrv_init(); - if(prussdrv_open(PRU_EVTOUT_0)) { - fprintf(stderr, "Failed to open PRU driver\n"); - return 1; - } - pruMemory = new PruMemory(pru_number, context); + pruManager = new PruManagerUio(pru_number, gRTAudioVerbose); + pruMemory = new PruMemory(pru_number, context, *pruManager); if(0 <= stopButtonPin){ stopButton.open(stopButtonPin, Gpio::INPUT, false); @@ -766,42 +761,25 @@ int PRU::start(char * const filename, const McaspRegisters& mcaspRegisters) #endif /* BELA_USE_RTDM */ pru_buffer_comm = pruMemory->getPruBufferComm(); initialisePruCommon(mcaspRegisters); - - unsigned int* pruCode; - unsigned int pruCodeSize; - switch((int)pruUsesMcaspIrq) // (int) is here to avoid stupid compiler warning - { - case false: - pruCode = (unsigned int*)NonIrqPruCode::getBinary(); - pruCodeSize = NonIrqPruCode::getBinarySize(); - break; - case true: - pruCode = (unsigned int*)IrqPruCode::getBinary(); - pruCodeSize = IrqPruCode::getBinarySize(); - // NOTE: we assume that something else has masked the McASP interrupts - // from ARM, or rather that no one else unmasked them. - // For instance, make sure the McASP driver does not get to get hold of them - // by NOT setting `interrupt-names = "rx", "tx";` in the overlay - break; - } + // NOTE: we assume that something else has masked the McASP interrupts + // from ARM, or rather that no one else unmasked them. + // For instance, make sure the McASP driver does not get to get hold of them + // by NOT setting `interrupt-names = "rx", "tx";` in the overlay /* Load and execute binary on PRU */ - if(filename[0] == '\0') { //if the string is empty, load the embedded code - if(gRTAudioVerbose) - printf("Using embedded PRU code\n"); - if(prussdrv_exec_code(pru_number, pruCode, pruCodeSize)) { - fprintf(stderr, "Failed to execute PRU code\n"); - return 1; - } - } else { - if(gRTAudioVerbose) - printf("Using PRU code from %s\n",filename); - if(prussdrv_exec_program(pru_number, filename)) { - fprintf(stderr, "Failed to execute PRU code from %s\n", filename); - return 1; - } + bool useEmbeddedPruCode = ("" == std::string(filename)); + unsigned int pruManager_ret = 0; + if(gRTAudioVerbose) + printf("Using %s %s PRU firmware\n", pruUsesMcaspIrq ? "McASP IRQ" : "Non-McASP IRQ", useEmbeddedPruCode ? "embedded" : filename); + if(useEmbeddedPruCode) + pruManager_ret = pruManager->start(pruUsesMcaspIrq); + else + pruManager_ret = pruManager->start(filename); + if(pruManager_ret) + { + fprintf(stderr, "Failed to execute PRU code\n"); + return 1; } - running = true; return 0; } @@ -1541,16 +1519,16 @@ void PRU::waitForFinish() // Turn off the PRU when done void PRU::disable() { - /* Disable PRU and close memory mapping*/ - prussdrv_pru_disable(pru_number); + /* Disable PRU and close memory mapping*/ + pruManager->stop(); running = false; } -// Exit the prussdrv subsystem (affects both PRUs) +// Exit the pru subsystem void PRU::exitPRUSS() { if(initialised) - prussdrv_exit(); + delete pruManager; initialised = false; } diff --git a/core/PruManager.cpp b/core/PruManager.cpp new file mode 100644 index 000000000..718e0b6e8 --- /dev/null +++ b/core/PruManager.cpp @@ -0,0 +1,95 @@ +/* + * PruManager.cpp + * + * Created on: July 3, 2021 + * Author: Dhruva Gole + */ + +#include "PruManager.h" +#include "MiscUtilities.h" +#include + +PruManager::PruManager(unsigned int pruNum, int v) +{ + /* based on the value of pru_num to choose: + * 0 for PRUSS1 core 0 + * 1 for PRUSS1 core 1 + * 2 for PRUSS2 core 0 + * 3 for PRUSS2 core 1 + */ + verbose = v; + pruss = pruNum / 2 + 1; + pruCore = pruNum % 2; + pruStringId = "PRU" + std::to_string(pruss) + "_" + std::to_string(pruCore); +} + +PruManager::~PruManager() +{} + +#include "../include/PruBinary.h" + +PruManagerUio::PruManagerUio(unsigned int pruNum, int v) : + PruManager(pruNum, v) +{ + prussdrv_init(); + if(prussdrv_open(PRU_EVTOUT_0)) { + fprintf(stderr, "Failed to open PRU driver\n"); + } +} + +int PruManagerUio::start(bool useMcaspIrq) +{ + unsigned int* pruCode; + unsigned int pruCodeSize; + switch((int)useMcaspIrq) // (int) is here to avoid stupid compiler warning + { + case false: + pruCode = (unsigned int*)NonIrqPruCode::getBinary(); + pruCodeSize = NonIrqPruCode::getBinarySize(); + break; + case true: + pruCode = (unsigned int*)IrqPruCode::getBinary(); + pruCodeSize = IrqPruCode::getBinarySize(); + break; + } + if(prussdrv_exec_code(pruCore, pruCode, pruCodeSize)) { + fprintf(stderr, "Failed to execute PRU code\n"); + return 1; + } + else + return 0; +} + +int PruManagerUio::start(const std::string& path) +{ + if(prussdrv_exec_program(pruCore, path.c_str())) { + return 1; + } + return 0; +} + +void PruManagerUio::stop(){ + if(verbose) + printf("Stopping %s\n", pruStringId.c_str()); + prussdrv_pru_disable(pruCore); +} + +void* PruManagerUio::getOwnMemory() +{ + void* pruDataRam; + int ret = prussdrv_map_prumem (pruCore == 0 ? PRUSS0_PRU0_DATARAM : PRUSS0_PRU1_DATARAM, (void**)&pruDataRam); + if(ret) + return NULL; + else + return pruDataRam; +} + +void* PruManagerUio::getSharedMemory() +{ + void* pruSharedRam; + int ret = prussdrv_map_prumem (PRUSS0_SHARED_DATARAM, (void **)&pruSharedRam); + if(ret) + return NULL; + else + return pruSharedRam; +} diff --git a/include/PRU.h b/include/PRU.h index ae12bbd77..e83f047ca 100644 --- a/include/PRU.h +++ b/include/PRU.h @@ -4,6 +4,7 @@ #include "Bela.h" #include "Gpio.h" #include "AudioCodec.h" +#include "PruManager.h" /** * Internal version of the BelaContext struct which does not have const @@ -177,6 +178,7 @@ class PRU // Exit the whole PRU subsystem void exitPRUSS(); + PruManager *pruManager; private: void initialisePruCommon(const McaspRegisters& mcaspRegisters); diff --git a/include/PruManager.h b/include/PruManager.h new file mode 100644 index 000000000..4b735950e --- /dev/null +++ b/include/PruManager.h @@ -0,0 +1,45 @@ +/* + * PruManager.h + * + * Support for interaction with PRU via + * (rproc+mmap) and/or (uio+libprussdrv) + * + * Created on: Jul 3, 2021 + * Author: Dhruva Gole + */ + +#include +#include +#include +#include "Mmap.h" + +class PruManager +{ +protected: + unsigned int pruss; + unsigned int pruCore; + int verbose; + std::string pruStringId; +public: + PruManager(unsigned int pruNum, int v); + virtual ~PruManager() = 0; + virtual int start(bool useMcaspIrq) = 0; + virtual int start(const std::string& path) = 0; + virtual void stop() = 0; + virtual void* getOwnMemory() = 0; + virtual void* getSharedMemory() = 0; +}; + +class PruManagerUio : public PruManager +{ +/* wrapper for libprussdrv for both start/stop and memory sharing + * It has the libprussdrv calls currently present in the codebase +*/ +public: + PruManagerUio(unsigned int pruNum, int v); + int start(bool useMcaspIrq); + int start(const std::string& path); + void stop(); + void* getOwnMemory(); + void* getSharedMemory(); +}; From 4ee5c20a8423c91be98da15b67eaad4e574bcdb7 Mon Sep 17 00:00:00 2001 From: Dhruva_Gole Date: Fri, 30 Jul 2021 10:44:53 +0100 Subject: [PATCH 130/148] PruManager: added support for RPROC (though ENABLE_PRU_UIO is still default) Co-authored-by: Giulio Moro --- Makefile | 2 +- core/PRU.cpp | 5 ++++ core/PruManager.cpp | 64 ++++++++++++++++++++++++++++++++++++++++++++ include/PruManager.h | 29 ++++++++++++++++++++ 4 files changed, 99 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 93c7351be..a5be59e56 100644 --- a/Makefile +++ b/Makefile @@ -294,7 +294,7 @@ ifeq ($(XENOMAI_VERSION),3) BELA_USE_DEFINE?=BELA_USE_RTDM endif -DEFAULT_COMMON_FLAGS := $(DEFAULT_XENOMAI_CFLAGS) -O3 -g -march=armv7-a -mtune=cortex-a8 -mfloat-abi=hard -mfpu=neon -ftree-vectorize -ffast-math -DNDEBUG -D$(BELA_USE_DEFINE) -I$(BASE_DIR)/resources/$(DEBIAN_VERSION)/include -save-temps=obj +DEFAULT_COMMON_FLAGS := $(DEFAULT_XENOMAI_CFLAGS) -O3 -g -march=armv7-a -mtune=cortex-a8 -mfloat-abi=hard -mfpu=neon -ftree-vectorize -ffast-math -DNDEBUG -D$(BELA_USE_DEFINE) -I$(BASE_DIR)/resources/$(DEBIAN_VERSION)/include -save-temps=obj -DENABLE_PRU_UIO=1 DEFAULT_CPPFLAGS := $(DEFAULT_COMMON_FLAGS) -std=c++11 DEFAULT_CFLAGS := $(DEFAULT_COMMON_FLAGS) -std=gnu11 BELA_LDFLAGS = -Llib/ diff --git a/core/PRU.cpp b/core/PRU.cpp index 44f580c6a..74d02a06d 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -383,7 +383,12 @@ int PRU::initialise(BelaHw newBelaHw, int pru_num, bool uniformSampleRate, int m pru_number = pru_num; /* Allocate and initialize memory */ +#if ENABLE_PRU_UIO == 1 pruManager = new PruManagerUio(pru_number, gRTAudioVerbose); +#endif // ENABLE_PRU_UIO +#if ENABLE_PRU_RPROC == 1 + pruManager = new PruManagerRprocMmap(pru_number, gRTAudioVerbose); +#endif // ENABLE_PRU_RPROC pruMemory = new PruMemory(pru_number, context, *pruManager); if(0 <= stopButtonPin){ diff --git a/core/PruManager.cpp b/core/PruManager.cpp index 718e0b6e8..09466055e 100644 --- a/core/PruManager.cpp +++ b/core/PruManager.cpp @@ -26,6 +26,69 @@ PruManager::PruManager(unsigned int pruNum, int v) PruManager::~PruManager() {} +#if ENABLE_PRU_RPROC == 1 +const std::vector prussOwnRamOffsets = {0x0, 0x2000}; +const uint32_t prussSharedRamOffset = 0x10000; + +PruManagerRprocMmap::PruManagerRprocMmap(unsigned int pruNum, int v) : + PruManager(pruNum, v) +{ + basePath = "/dev/remoteproc/pruss" + std::to_string(pruss) + "-core" + std::to_string(pruCore) + "/"; + statePath = basePath + "state"; + firmwarePath = basePath + "firmware"; + firmware = "am57xx-pru" + std::to_string(pruss) + "_" + std::to_string(pruCore) + "-fw"; + +#warning Untested PRU addresses for am3358 + prussAddresses.push_back(0x4a334000); + prussAddresses.push_back(0x4a338000); +} + +void PruManagerRprocMmap::stop() +{ + // performs echo stop > state + if(verbose) + printf("Stopping %s\n", pruStringId.c_str()); + IoUtils::writeTextFile(statePath, "stop"); +} + +int PruManagerRprocMmap::start(bool useMcaspIrq) +{ +#if (defined(firmwareBelaRProcNoMcaspIrq) && defined(firmwareBelaRProcMcaspIrq)) + std::string firmwareBela = useMcaspIrq ? firmwareBelaRProcMcaspIrq : firmwareBelaRProcNoMcaspIrq; // Incoming strings from Makefile + return start(firmwareBela); +#else +#error No PRU firmware defined. Pass the name of firmware.out file using firmwareBelaRProcNoMcaspIrq= and firmwareBelaRProcMcaspIrq= +#endif +} + +int PruManagerRprocMmap::start(const std::string& path) +{ + stop(); + std::string symlinkTarget = "/lib/firmware/" + firmware; + std::string firmwareCopyCommand = "ln -s -f " + path + " " + symlinkTarget; + system(firmwareCopyCommand.c_str()); + if(verbose) + printf("Loading firmware into %s: %s symlinked from %s\n", pruStringId.c_str(), symlinkTarget.c_str(), path.c_str()); + IoUtils::writeTextFile(firmwarePath, firmware); // reload the new fw in PRU + // performs echo start > state + if(verbose) + printf("Starting %s\n", pruStringId.c_str()); + IoUtils::writeTextFile(statePath, "start"); + return 0; // TODO: If system returns any error then detect it and then return 1 instead +} + +void* PruManagerRprocMmap::getOwnMemory() +{ + return ownMemory.map(prussAddresses[pruss - 1] + prussOwnRamOffsets[pruCore], 0x2000); +} + +void* PruManagerRprocMmap::getSharedMemory() +{ + return sharedMemory.map(prussAddresses[pruss - 1] + prussSharedRamOffset, 0x8000); +} +#endif // ENABLE_PRU_RPROC + +#if ENABLE_PRU_UIO == 1 #include "../include/PruBinary.h" PruManagerUio::PruManagerUio(unsigned int pruNum, int v) : @@ -93,3 +156,4 @@ void* PruManagerUio::getSharedMemory() else return pruSharedRam; } +#endif // ENABLE_PRU_UIO diff --git a/include/PruManager.h b/include/PruManager.h index 4b735950e..589b828ac 100644 --- a/include/PruManager.h +++ b/include/PruManager.h @@ -9,7 +9,11 @@ */ #include + +#if ENABLE_PRU_UIO == 1 #include +#endif + #include #include "Mmap.h" @@ -30,6 +34,29 @@ class PruManager virtual void* getSharedMemory() = 0; }; +#if ENABLE_PRU_RPROC == 1 +class PruManagerRprocMmap : public PruManager +{ +// use rproc for start/stop and mmap for memory sharing +public: + PruManagerRprocMmap(unsigned int pruNum, int v); + void stop(); + int start(bool useMcaspIrq); + int start(const std::string& path); + void* getOwnMemory(); + void* getSharedMemory(); +private: + std::vector prussAddresses; + std::string basePath; + std::string statePath; + std::string firmwarePath; + std::string firmware; + Mmap ownMemory; + Mmap sharedMemory; +}; +#endif // ENABLE_PRU_RPROC + +#if ENABLE_PRU_UIO == 1 class PruManagerUio : public PruManager { /* wrapper for libprussdrv for both start/stop and memory sharing @@ -43,3 +70,5 @@ class PruManagerUio : public PruManager void* getOwnMemory(); void* getSharedMemory(); }; + +#endif // ENABLE_PRU_UIO From 601f0385ff6abd054a15e3977f322c0736897a2f Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Fri, 30 Jul 2021 18:21:35 +0000 Subject: [PATCH 131/148] PruManager: refactored firwmare name. More error checks in the rproc starting process --- core/PruManager.cpp | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/core/PruManager.cpp b/core/PruManager.cpp index 09466055e..16f766a31 100644 --- a/core/PruManager.cpp +++ b/core/PruManager.cpp @@ -27,6 +27,8 @@ PruManager::~PruManager() {} #if ENABLE_PRU_RPROC == 1 +#include + const std::vector prussOwnRamOffsets = {0x0, 0x2000}; const uint32_t prussSharedRamOffset = 0x10000; @@ -36,11 +38,11 @@ PruManagerRprocMmap::PruManagerRprocMmap(unsigned int pruNum, int v) : basePath = "/dev/remoteproc/pruss" + std::to_string(pruss) + "-core" + std::to_string(pruCore) + "/"; statePath = basePath + "state"; firmwarePath = basePath + "firmware"; - firmware = "am57xx-pru" + std::to_string(pruss) + "_" + std::to_string(pruCore) + "-fw"; - #warning Untested PRU addresses for am3358 prussAddresses.push_back(0x4a334000); prussAddresses.push_back(0x4a338000); + firmware = "am335x"; + firmware += "-pru" + std::to_string(pruss) + "_" + std::to_string(pruCore) + "-fw"; } void PruManagerRprocMmap::stop() @@ -66,15 +68,37 @@ int PruManagerRprocMmap::start(const std::string& path) stop(); std::string symlinkTarget = "/lib/firmware/" + firmware; std::string firmwareCopyCommand = "ln -s -f " + path + " " + symlinkTarget; - system(firmwareCopyCommand.c_str()); + int wstatus = system(firmwareCopyCommand.c_str()); + int ret = !WIFEXITED(wstatus) ? -1 : WEXITSTATUS(wstatus); + if (ret) + { + fprintf(stderr, "Error while executing `%s` to load PRU: %d\n", firmwareCopyCommand.c_str(), ret); + return -1; + } if(verbose) printf("Loading firmware into %s: %s symlinked from %s\n", pruStringId.c_str(), symlinkTarget.c_str(), path.c_str()); - IoUtils::writeTextFile(firmwarePath, firmware); // reload the new fw in PRU + // reload the new fw in PRU + if(IoUtils::writeTextFile(firmwarePath, firmware)) + { + fprintf(stderr, "PruManagerRprocMmap: unable to write %s to %s\n", firmware.c_str(), firmwarePath.c_str()); + return -1; + } // performs echo start > state if(verbose) printf("Starting %s\n", pruStringId.c_str()); - IoUtils::writeTextFile(statePath, "start"); - return 0; // TODO: If system returns any error then detect it and then return 1 instead + if(IoUtils::writeTextFile(statePath, "start")) + { + fprintf(stderr, "PruManagerRprocMmap: unable to write %s to %s\n", "start", statePath.c_str()); + return -1; + } + usleep(10000); // not sure if needed, but it won't hurt to wait to give it time to load the firmware and become "running" + std::string state = IoUtils::readTextFile(statePath); + if(state != "running\n") + { + fprintf(stderr, "PruManagerRprocMmap: we started PRU but state in %s is %s\n", statePath.c_str(), state.c_str()); + return -1; + } + return 0; } void* PruManagerRprocMmap::getOwnMemory() From e2785a5f0f4ffb0fcc6400f7a77b652825d1ab09 Mon Sep 17 00:00:00 2001 From: Dhruva_Gole Date: Thu, 29 Jul 2021 21:11:54 +0530 Subject: [PATCH 132/148] rproc: create resources/rproc-build which contains helpful files for building PRU firmware for rproc These files are taken from https://github.com/beagleboard/cloud9-examples@eed6500 Co-authored-by: Giulio Moro --- resources/rproc-build/am335x_pru.cmd | 87 +++++++++++++++++++ resources/rproc-build/am57xx_pru.cmd | 86 ++++++++++++++++++ .../rproc-build/common/resource_table_empty.h | 39 +++++++++ resources/rproc-build/rproc-template.c | 10 +++ 4 files changed, 222 insertions(+) create mode 100644 resources/rproc-build/am335x_pru.cmd create mode 100644 resources/rproc-build/am57xx_pru.cmd create mode 100644 resources/rproc-build/common/resource_table_empty.h create mode 100644 resources/rproc-build/rproc-template.c diff --git a/resources/rproc-build/am335x_pru.cmd b/resources/rproc-build/am335x_pru.cmd new file mode 100644 index 000000000..67005475f --- /dev/null +++ b/resources/rproc-build/am335x_pru.cmd @@ -0,0 +1,87 @@ +/****************************************************************************/ +/* AM335x_PRU.cmd */ +/* Copyright (c) 2015 Texas Instruments Incorporated */ +/* */ +/* Description: This file is a linker command file that can be used for */ +/* linking PRU programs built with the C compiler and */ +/* the resulting .out file on an AM335x device. */ +/****************************************************************************/ + +-cr /* Link using C conventions */ + +/* Specify the System Memory Map */ +MEMORY +{ + PAGE 0: + PRU_IMEM : org = 0x00000000 len = 0x00002000 /* 8kB PRU0 Instruction RAM */ + + PAGE 1: + + /* RAM */ + + PRU_DMEM_0_1 : org = 0x00000000 len = 0x00002000 CREGISTER=24 /* 8kB PRU Data RAM 0_1 */ + PRU_DMEM_1_0 : org = 0x00002000 len = 0x00002000 CREGISTER=25 /* 8kB PRU Data RAM 1_0 */ + + PAGE 2: + PRU_SHAREDMEM : org = 0x00010000 len = 0x00003000 CREGISTER=28 /* 12kB Shared RAM */ + + DDR : org = 0x80000000 len = 0x00000100 CREGISTER=31 + L3OCMC : org = 0x40000000 len = 0x00010000 CREGISTER=30 + + + /* Peripherals */ + + PRU_CFG : org = 0x00026000 len = 0x00000044 CREGISTER=4 + PRU_ECAP : org = 0x00030000 len = 0x00000060 CREGISTER=3 + PRU_IEP : org = 0x0002E000 len = 0x0000031C CREGISTER=26 + PRU_INTC : org = 0x00020000 len = 0x00001504 CREGISTER=0 + PRU_UART : org = 0x00028000 len = 0x00000038 CREGISTER=7 + + DCAN0 : org = 0x481CC000 len = 0x000001E8 CREGISTER=14 + DCAN1 : org = 0x481D0000 len = 0x000001E8 CREGISTER=15 + DMTIMER2 : org = 0x48040000 len = 0x0000005C CREGISTER=1 + PWMSS0 : org = 0x48300000 len = 0x000002C4 CREGISTER=18 + PWMSS1 : org = 0x48302000 len = 0x000002C4 CREGISTER=19 + PWMSS2 : org = 0x48304000 len = 0x000002C4 CREGISTER=20 + GEMAC : org = 0x4A100000 len = 0x0000128C CREGISTER=9 + I2C1 : org = 0x4802A000 len = 0x000000D8 CREGISTER=2 + I2C2 : org = 0x4819C000 len = 0x000000D8 CREGISTER=17 + MBX0 : org = 0x480C8000 len = 0x00000140 CREGISTER=22 + MCASP0_DMA : org = 0x46000000 len = 0x00000100 CREGISTER=8 + MCSPI0 : org = 0x48030000 len = 0x000001A4 CREGISTER=6 + MCSPI1 : org = 0x481A0000 len = 0x000001A4 CREGISTER=16 + MMCHS0 : org = 0x48060000 len = 0x00000300 CREGISTER=5 + SPINLOCK : org = 0x480CA000 len = 0x00000880 CREGISTER=23 + TPCC : org = 0x49000000 len = 0x00001098 CREGISTER=29 + UART1 : org = 0x48022000 len = 0x00000088 CREGISTER=11 + UART2 : org = 0x48024000 len = 0x00000088 CREGISTER=12 + + RSVD10 : org = 0x48318000 len = 0x00000100 CREGISTER=10 + RSVD13 : org = 0x48310000 len = 0x00000100 CREGISTER=13 + RSVD21 : org = 0x00032400 len = 0x00000100 CREGISTER=21 + RSVD27 : org = 0x00032000 len = 0x00000100 CREGISTER=27 + +} + +/* Specify the sections allocation into memory */ +SECTIONS { + /* Forces _c_int00 to the start of PRU IRAM. Not necessary when loading + an ELF file, but useful when loading a binary */ + .text:_c_int00* > 0x0, PAGE 0 + + .text > PRU_IMEM, PAGE 0 + .stack > PRU_DMEM_0_1, PAGE 1 + .bss > PRU_DMEM_0_1, PAGE 1 + .cio > PRU_DMEM_0_1, PAGE 1 + .data > PRU_DMEM_0_1, PAGE 1 + .switch > PRU_DMEM_0_1, PAGE 1 + .sysmem > PRU_DMEM_0_1, PAGE 1 + .cinit > PRU_DMEM_0_1, PAGE 1 + .rodata > PRU_DMEM_0_1, PAGE 1 + .rofardata > PRU_DMEM_0_1, PAGE 1 + .farbss > PRU_DMEM_0_1, PAGE 1 + .fardata > PRU_DMEM_0_1, PAGE 1 + + .resource_table > PRU_DMEM_0_1, PAGE 1 + .init_pins > PRU_DMEM_0_1, PAGE 1 +} \ No newline at end of file diff --git a/resources/rproc-build/am57xx_pru.cmd b/resources/rproc-build/am57xx_pru.cmd new file mode 100644 index 000000000..85e78fb04 --- /dev/null +++ b/resources/rproc-build/am57xx_pru.cmd @@ -0,0 +1,86 @@ +/****************************************************************************/ +/* AM57xx_PRU.cmd */ +/* Copyright (c) 2015 Texas Instruments Incorporated */ +/* */ +/* Description: This file is a linker command file that can be used for */ +/* linking PRU programs built with the C compiler and */ +/* the resulting .out file on an AM57xx device. */ +/****************************************************************************/ + +-cr /* Link using C conventions */ + +/* Specify the System Memory Map */ +MEMORY +{ + PAGE 0: + PRU_IMEM : org = 0x00000000 len = 0x00003000 /* 12kB PRU-ICSS1 Instruction RAM */ + + PAGE 1: + + /* RAM */ + + PRU_DMEM_0_1 : org = 0x00000000 len = 0x00002000 CREGISTER=24 /* 8kB PRU Data RAM 0_1 */ + PRU_DMEM_1_0 : org = 0x00002000 len = 0x00002000 CREGISTER=25 /* 8kB PRU Data RAM 1_0 */ + + PAGE 2: + PRU_SHAREDMEM : org = 0x00010000 len = 0x00008000 CREGISTER=28 /* 32kB Shared RAM */ + + DDR : org = 0x80000000 len = 0x00010000 CREGISTER=31 + L3OCMC : org = 0x40000000 len = 0x00010000 CREGISTER=30 + + + /* Peripherals */ + + PRU_CFG : org = 0x00026000 len = 0x00000120 CREGISTER=4 + PRU_ECAP : org = 0x00030000 len = 0x00000060 CREGISTER=3 + PRU_IEP : org = 0x0002E000 len = 0x0000031C CREGISTER=26 + PRU_INTC : org = 0x00020000 len = 0x00001504 CREGISTER=0 + PRU_UART : org = 0x00028000 len = 0x00000038 CREGISTER=7 + + MCASP3_DMA : org = 0x46000000 len = 0x00000100 CREGISTER=8 + I2C3 : org = 0x48060000 len = 0x00000300 CREGISTER=5 + + RSVD1 : org = 0x48040000 len = 0x0000005C CREGISTER=1 + RSVD2 : org = 0x4802A000 len = 0x000000D8 CREGISTER=2 + RSVD6 : org = 0x48030000 len = 0x000001A4 CREGISTER=6 + RSVD9 : org = 0x4A100000 len = 0x0000128C CREGISTER=9 + RSVD10 : org = 0x48318000 len = 0x00000100 CREGISTER=10 + RSVD11 : org = 0x48022000 len = 0x00000088 CREGISTER=11 + RSVD12 : org = 0x48024000 len = 0x00000088 CREGISTER=12 + RSVD13 : org = 0x48310000 len = 0x00000100 CREGISTER=13 + RSVD14 : org = 0x481CC000 len = 0x000001E8 CREGISTER=14 + RSVD15 : org = 0x481D0000 len = 0x000001E8 CREGISTER=15 + RSVD16 : org = 0x481A0000 len = 0x000001A4 CREGISTER=16 + RSVD17 : org = 0x4819C000 len = 0x000000D8 CREGISTER=17 + RSVD18 : org = 0x48300000 len = 0x000002C4 CREGISTER=18 + RSVD19 : org = 0x48302000 len = 0x000002C4 CREGISTER=19 + RSVD20 : org = 0x48304000 len = 0x000002C4 CREGISTER=20 + RSVD21 : org = 0x00032400 len = 0x00000100 CREGISTER=21 + RSVD22 : org = 0x480C8000 len = 0x00000140 CREGISTER=22 + RSVD23 : org = 0x480CA000 len = 0x00000880 CREGISTER=23 + RSVD27 : org = 0x00032000 len = 0x00000100 CREGISTER=27 + RSVD29 : org = 0x49000000 len = 0x00001098 CREGISTER=29 +} + +/* Specify the sections allocation into memory */ +SECTIONS { + /* Forces _c_int00 to the start of PRU IRAM. Not necessary when loading + an ELF file, but useful when loading a binary */ + .text:_c_int00* > 0x0, PAGE 0 + + .text > PRU_IMEM, PAGE 0 + .stack > PRU_DMEM_0_1, PAGE 1 + .bss > PRU_DMEM_0_1, PAGE 1 + .cio > PRU_DMEM_0_1, PAGE 1 + .data > PRU_DMEM_0_1, PAGE 1 + .switch > PRU_DMEM_0_1, PAGE 1 + .sysmem > PRU_DMEM_0_1, PAGE 1 + .cinit > PRU_DMEM_0_1, PAGE 1 + .rodata > PRU_DMEM_0_1, PAGE 1 + .rofardata > PRU_DMEM_0_1, PAGE 1 + .farbss > PRU_DMEM_0_1, PAGE 1 + .fardata > PRU_DMEM_0_1, PAGE 1 + + .resource_table > PRU_DMEM_0_1, PAGE 1 + .init_pins > PRU_DMEM_0_1, PAGE 1 +} diff --git a/resources/rproc-build/common/resource_table_empty.h b/resources/rproc-build/common/resource_table_empty.h new file mode 100644 index 000000000..07e97d9b3 --- /dev/null +++ b/resources/rproc-build/common/resource_table_empty.h @@ -0,0 +1,39 @@ +/* + * ======== resource_table_empty.h ======== + * + * Define the resource table entries for all PRU cores. This will be + * incorporated into corresponding base images, and used by the remoteproc + * on the host-side to allocated/reserve resources. Note the remoteproc + * driver requires that all PRU firmware be built with a resource table. + * + * This file contains an empty resource table. It can be used either as: + * + * 1) A template, or + * 2) As-is if a PRU application does not need to configure PRU_INTC + * or interact with the rpmsg driver + * + */ + +#ifndef _RSC_TABLE_PRU_H_ +#define _RSC_TABLE_PRU_H_ + +#include +#include + +struct my_resource_table { + struct resource_table base; + + uint32_t offset[1]; /* Should match 'num' in actual definition */ +}; + +#pragma DATA_SECTION(pru_remoteproc_ResourceTable, ".resource_table") +#pragma RETAIN(pru_remoteproc_ResourceTable) +struct my_resource_table pru_remoteproc_ResourceTable = { + 1, /* we're the first version that implements this */ + 0, /* number of entries in the table */ + 0, 0, /* reserved, must be zero */ + 0, /* offset[0] */ +}; + +#endif /* _RSC_TABLE_PRU_H_ */ + diff --git a/resources/rproc-build/rproc-template.c b/resources/rproc-build/rproc-template.c new file mode 100644 index 000000000..3553316f1 --- /dev/null +++ b/resources/rproc-build/rproc-template.c @@ -0,0 +1,10 @@ +#include "resource_table_empty.h" + +void _c_int00(void) +{ + __asm__ __volatile__ + ( +#include "included_assembly.h" + ); +} + From a5d3bc27eca2bccaa5fc51fb0de4802ce208f7e2 Mon Sep 17 00:00:00 2001 From: Dhruva_Gole Date: Fri, 30 Jul 2021 10:47:23 +0100 Subject: [PATCH 133/148] Added initial support for AM572x (BBAI), using rproc for PRU loading. Doesn't yet build rproc firmware. Co-authored-by: Giulio Moro --- Makefile | 19 +++++++++++++- core/Mcasp.cpp | 4 +++ core/PruManager.cpp | 6 +++++ include/bela_hw_settings.h | 4 +++ pru/pru_rtaudio.p | 52 +++++++++++++++++++++++++++++++++++++- 5 files changed, 83 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index a5be59e56..609b6475a 100644 --- a/Makefile +++ b/Makefile @@ -294,7 +294,24 @@ ifeq ($(XENOMAI_VERSION),3) BELA_USE_DEFINE?=BELA_USE_RTDM endif -DEFAULT_COMMON_FLAGS := $(DEFAULT_XENOMAI_CFLAGS) -O3 -g -march=armv7-a -mtune=cortex-a8 -mfloat-abi=hard -mfpu=neon -ftree-vectorize -ffast-math -DNDEBUG -D$(BELA_USE_DEFINE) -I$(BASE_DIR)/resources/$(DEBIAN_VERSION)/include -save-temps=obj -DENABLE_PRU_UIO=1 +IS_AM572x = $(shell grep -q AI /proc/device-tree/model && echo '-DIS_AM572x') + +ifeq ($(AT),) + $(info AI flag = $(IS_AM572x)) +endif + +# Flag for using/ not using (UIO+prussdrv)/(RPROC+Mmap) +ifneq (,$(findstring IS,$(IS_AM572x))) + ENABLE_PRU_UIO = 0 + ENABLE_PRU_RPROC = 1 + firmwareBelaRProcNoMcaspIrq = $(BELA_DIR)/build/pru/pru_rtaudio_bin.out + firmwareBelaRProcMcaspIrq = $(BELA_DIR)/build/pru/pru_rtaudio_irq_bin.out +else + ENABLE_PRU_UIO = 1 + ENABLE_PRU_RPROC = 0 +endif + +DEFAULT_COMMON_FLAGS := $(DEFAULT_XENOMAI_CFLAGS) -O3 -g -march=armv7-a -mtune=cortex-a8 -mfloat-abi=hard -mfpu=neon -ftree-vectorize -ffast-math -DNDEBUG -D$(BELA_USE_DEFINE) -I$(BASE_DIR)/resources/$(DEBIAN_VERSION)/include -save-temps=obj $(IS_AM572x) -DENABLE_PRU_UIO=$(ENABLE_PRU_UIO) -DENABLE_PRU_RPROC=$(ENABLE_PRU_RPROC) -DfirmwareBelaRProcMcaspIrq=\"$(firmwareBelaRProcMcaspIrq)\" -DfirmwareBelaRProcNoMcaspIrq=\"$(firmwareBelaRProcNoMcaspIrq)\" DEFAULT_CPPFLAGS := $(DEFAULT_COMMON_FLAGS) -std=c++11 DEFAULT_CFLAGS := $(DEFAULT_COMMON_FLAGS) -std=gnu11 BELA_LDFLAGS = -Llib/ diff --git a/core/Mcasp.cpp b/core/Mcasp.cpp index 796d9cdc3..049303d09 100644 --- a/core/Mcasp.cpp +++ b/core/Mcasp.cpp @@ -8,7 +8,11 @@ McaspConfig::McaspConfig() { params = {0}; +#ifdef IS_AM572x + params.auxClkIn = 20000000; // workaround due to unexpected sys_clk2 frequency +#else params.auxClkIn = 24000000; +#endif // IS_AM572x } double McaspConfig::getValidAhclk(double desiredClk, unsigned int* outDiv) diff --git a/core/PruManager.cpp b/core/PruManager.cpp index 16f766a31..1db195ca6 100644 --- a/core/PruManager.cpp +++ b/core/PruManager.cpp @@ -38,10 +38,16 @@ PruManagerRprocMmap::PruManagerRprocMmap(unsigned int pruNum, int v) : basePath = "/dev/remoteproc/pruss" + std::to_string(pruss) + "-core" + std::to_string(pruCore) + "/"; statePath = basePath + "state"; firmwarePath = basePath + "firmware"; +#ifdef IS_AM572x + prussAddresses.push_back(0x4b200000); + prussAddresses.push_back(0x4b280000); + firmware = "am57xx"; +#else // IS_AM572x #warning Untested PRU addresses for am3358 prussAddresses.push_back(0x4a334000); prussAddresses.push_back(0x4a338000); firmware = "am335x"; +#endif // IS_AM572x firmware += "-pru" + std::to_string(pruss) + "_" + std::to_string(pruCore) + "-fw"; } diff --git a/include/bela_hw_settings.h b/include/bela_hw_settings.h index 12d68a5e7..d0c8c96af 100644 --- a/include/bela_hw_settings.h +++ b/include/bela_hw_settings.h @@ -1,5 +1,9 @@ #pragma once +#ifdef IS_AM572x // BBAI +const unsigned int codecI2cBus = 3; // Bus for TLV320AIC3104 codec +#else // BBB const unsigned int codecI2cBus = 2; // Bus for TLV320AIC3104 codec +#endif // IS_AM572x const unsigned int codecI2cAddress = 0x18; // Address of TLV320AIC3104 codec const unsigned int kBelaCapeButtonPin = 115; //P9.27 / P2.34 connected to The Button const unsigned int kAmplifierMutePin = 61; // P8.26 controls amplifier mute diff --git a/pru/pru_rtaudio.p b/pru/pru_rtaudio.p index c8a2222fe..20a15ffac 100644 --- a/pru/pru_rtaudio.p +++ b/pru/pru_rtaudio.p @@ -5,15 +5,26 @@ #define DBOX_CAPE // Define this to use new cape hardware +#ifdef IS_AM572x +#define CLOCK_BASE 0x4A005000 +#define CLOCK_MCASP0 0x550 +#define CLOCK_MCASP_VALUE 0x7000002 +#else // IS_AM572x #define CLOCK_BASE 0x44E00000 #define CLOCK_MCASP0 0x34 #define CLOCK_MCASP_VALUE 0x30002 // should probably be just 0x2 +#endif // IS_AM572x #define CLOCK_SPI0 0x4C #define CLOCK_SPI1 0x50 #define CLOCK_L4LS 0x60 +#ifdef IS_AM572x +#define SPI0_BASE 0x4809A100 +#define SPI1_BASE 0x480B8100 +#else #define SPI0_BASE 0x48030100 #define SPI1_BASE 0x481A0100 +#endif #define SPI_BASE SPI0_BASE #define SPI_SYSCONFIG 0x10 @@ -84,8 +95,11 @@ #define SHARED_COMM_MEM_BASE 0x00010000 // Location where comm flags are written // General constants for McASP peripherals (used for audio codec) +#ifdef IS_AM572x +#define MCASP0_BASE 0x48460000 // pg 6118 of AM57x Manual, it actually is MCASP1 but temporarily keeping as 0 for testing ease +#else #define MCASP0_BASE 0x48038000 -#define MCASP1_BASE 0x4803C000 +#endif #define MCASP_PWRIDLESYSCONFIG 0x04 #define MCASP_PFUNC 0x10 @@ -128,18 +142,31 @@ #define MCASP_SRCTL3 0x18C #define MCASP_SRCTL4 0x190 #define MCASP_SRCTL5 0x194 +#define MCASP_SRCTL6 0x198 +#define MCASP_SRCTL7 0x19C +#define MCASP_SRCTL8 0x1A0 +#define MCASP_SRCTL9 0x1A4 +#define MCASP_SRCTL10 0x1A8 +#define MCASP_SRCTL11 0x1AC +#define MCASP_SRCTL12 0x1B0 +#define MCASP_SRCTL13 0x1B4 +#define MCASP_SRCTL14 0x1B8 +#define MCASP_SRCTL15 0x1BC #define MCASP_XBUF0 0x200 #define MCASP_XBUF1 0x204 #define MCASP_XBUF2 0x208 #define MCASP_XBUF3 0x20C #define MCASP_XBUF4 0x210 #define MCASP_XBUF5 0x214 +#define MCASP_XBUF10 0x228 +#define MCASP_XBUF11 0x22C #define MCASP_RBUF0 0x280 #define MCASP_RBUF1 0x284 #define MCASP_RBUF2 0x288 #define MCASP_RBUF3 0x28C #define MCASP_RBUF4 0x290 #define MCASP_RBUF5 0x294 +#define MCASP_RBUF10 0x2A8 #define MCASP_WFIFOCTL 0x1000 #define MCASP_WFIFOSTS 0x1004 #define MCASP_RFIFOCTL 0x1008 @@ -152,10 +179,17 @@ // Constants used for this particular audio setup #define MCASP_BASE MCASP0_BASE #ifdef DBOX_CAPE +#ifdef IS_AM572x +#define MCASP_SRCTL_X MCASP_SRCTL11 // Ser. 11 is transmitter +#define MCASP_SRCTL_R MCASP_SRCTL10 // Ser. 10 is receiver +#define MCASP_XBUF MCASP_XBUF11 +#define MCASP_RBUF MCASP_RBUF10 +#else // IS_AM572x #define MCASP_SRCTL_X MCASP_SRCTL2 // Ser. 2 is transmitter #define MCASP_SRCTL_R MCASP_SRCTL0 // Ser. 0 is receiver #define MCASP_XBUF MCASP_XBUF2 #define MCASP_RBUF MCASP_RBUF0 +#endif // IS_AM572x #else #define MCASP_SRCTL_X MCASP_SRCTL3 // Ser. 3 is transmitter #define MCASP_SRCTL_R MCASP_SRCTL2 // Ser. 2 is receiver @@ -169,7 +203,11 @@ #define MCASP_PIN_AMUTE (1 << 25) // Also, 0 to 3 are XFR0 to XFR3 #ifdef DBOX_CAPE +#ifdef IS_AM572x +#define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 11) // AHCLKX and AXR2 outputs +#else // IS_AM572x #define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 2) // AHCLKX and AXR2 outputs +#endif // IS_AM572x #else #define MCASP_OUTPUT_PINS (1 << 3) // Which pins are outputs #endif @@ -885,6 +923,18 @@ MCASP_CLOCK_ENABLE_LOOP: MCASP_REG_WRITE_EXT MCASP_SRCTL3, 0 MCASP_REG_WRITE_EXT MCASP_SRCTL4, 0 MCASP_REG_WRITE_EXT MCASP_SRCTL5, 0 +#ifdef IS_AM572x + MCASP_REG_WRITE_EXT MCASP_SRCTL6, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL7, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL8, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL9, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL10, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL11, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL12, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL13, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL14, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL15, 0 +#endif // IS_AM572x MCASP_REG_WRITE MCASP_PWRIDLESYSCONFIG, 0x02 // Power on MCASP_REG_WRITE MCASP_PFUNC, 0x00 // All pins are McASP From 66c0c821651d9f34cd2c4cd6939d667cb5fec514 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Thu, 29 Jul 2021 20:59:20 +0000 Subject: [PATCH 134/148] Makefile: simplified checks for IS_AM572x. Distinguished between Rproc/Uio/board. Removed dependency on libprussdrv and PruBinary.o when not using UIO --- Makefile | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 609b6475a..e91148fcc 100644 --- a/Makefile +++ b/Makefile @@ -294,28 +294,43 @@ ifeq ($(XENOMAI_VERSION),3) BELA_USE_DEFINE?=BELA_USE_RTDM endif -IS_AM572x = $(shell grep -q AI /proc/device-tree/model && echo '-DIS_AM572x') - -ifeq ($(AT),) - $(info AI flag = $(IS_AM572x)) -endif +IS_AM572x ?= $(shell grep -q AI /proc/device-tree/model && echo 1 || echo 0) # Flag for using/ not using (UIO+prussdrv)/(RPROC+Mmap) -ifneq (,$(findstring IS,$(IS_AM572x))) +ifeq (1,$(strip $(IS_AM572x))) ENABLE_PRU_UIO = 0 ENABLE_PRU_RPROC = 1 - firmwareBelaRProcNoMcaspIrq = $(BELA_DIR)/build/pru/pru_rtaudio_bin.out - firmwareBelaRProcMcaspIrq = $(BELA_DIR)/build/pru/pru_rtaudio_irq_bin.out + BOARD_COMMON_FLAGS = -DIS_AM572x else ENABLE_PRU_UIO = 1 ENABLE_PRU_RPROC = 0 + BOARD_COMMON_FLAGS = +endif + +ifeq (,$(AT)) + $(info BOARD IS_AM572x? $(IS_AM572x)) +endif + +ifeq (1,$(strip $(ENABLE_PRU_RPROC))) + firmwareBelaRProcNoMcaspIrq ?= $(BELA_DIR)/build/pru/pru_rtaudio_bin.out + firmwareBelaRProcMcaspIrq ?= $(BELA_DIR)/build/pru/pru_rtaudio_irq_bin.out + BOARD_CORE_LDLIBS = + BOARD_CORE_CORE_OBJS = +else + BOARD_CORE_CPP_SRCS_FILTER_OUT := +endif +ifeq (1,$(strip $(ENABLE_PRU_UIO))) + BOARD_CORE_LDLIBS = -lprussdrv + BOARD_CORE_CORE_OBJS = build/core/PruBinary.o +else + BOARD_CORE_CPP_SRCS_FILTER_OUT := core/PruBinary.cpp endif -DEFAULT_COMMON_FLAGS := $(DEFAULT_XENOMAI_CFLAGS) -O3 -g -march=armv7-a -mtune=cortex-a8 -mfloat-abi=hard -mfpu=neon -ftree-vectorize -ffast-math -DNDEBUG -D$(BELA_USE_DEFINE) -I$(BASE_DIR)/resources/$(DEBIAN_VERSION)/include -save-temps=obj $(IS_AM572x) -DENABLE_PRU_UIO=$(ENABLE_PRU_UIO) -DENABLE_PRU_RPROC=$(ENABLE_PRU_RPROC) -DfirmwareBelaRProcMcaspIrq=\"$(firmwareBelaRProcMcaspIrq)\" -DfirmwareBelaRProcNoMcaspIrq=\"$(firmwareBelaRProcNoMcaspIrq)\" +DEFAULT_COMMON_FLAGS := $(DEFAULT_XENOMAI_CFLAGS) -O3 -g -march=armv7-a -mtune=cortex-a8 -mfloat-abi=hard -mfpu=neon -ftree-vectorize -ffast-math -DNDEBUG -D$(BELA_USE_DEFINE) -I$(BASE_DIR)/resources/$(DEBIAN_VERSION)/include -save-temps=obj -DENABLE_PRU_UIO=$(ENABLE_PRU_UIO) -DENABLE_PRU_RPROC=$(ENABLE_PRU_RPROC) -DfirmwareBelaRProcMcaspIrq='"$(firmwareBelaRProcMcaspIrq)"' -DfirmwareBelaRProcNoMcaspIrq='"$(firmwareBelaRProcNoMcaspIrq)"' $(BOARD_COMMON_FLAGS) DEFAULT_CPPFLAGS := $(DEFAULT_COMMON_FLAGS) -std=c++11 DEFAULT_CFLAGS := $(DEFAULT_COMMON_FLAGS) -std=gnu11 BELA_LDFLAGS = -Llib/ -BELA_CORE_LDLIBS = $(DEFAULT_XENOMAI_LDFLAGS) -lprussdrv -lstdc++ # libraries needed by core code (libbela.so) +BELA_CORE_LDLIBS = $(DEFAULT_XENOMAI_LDFLAGS) $(BOARD_CORE_LDLIBS) -lstdc++ # libraries needed by core code (libbela.so) BELA_EXTRA_LDLIBS =$(DEFAULT_XENOMAI_LDFLAGS) -lasound -lseasocks -lNE10 # additional libraries needed by extra code (libbelaextra.so) BELA_LDLIBS = $(BELA_CORE_LDLIBS) $(BELA_EXTRA_LDLIBS) ifeq ($(PROJECT_TYPE),libpd) @@ -410,9 +425,10 @@ CORE_C_SRCS = $(wildcard core/*.c) CORE_OBJS := $(addprefix build/core/,$(notdir $(CORE_C_SRCS:.c=.o))) ALL_DEPS += $(addprefix build/core/,$(notdir $(CORE_C_SRCS:.c=.d))) -CORE_CPP_SRCS = $(filter-out core/default_main.cpp core/default_libpd_render.cpp, $(wildcard core/*.cpp)) +CORE_CPP_SRCS := $(filter-out core/default_main.cpp core/default_libpd_render.cpp, $(wildcard core/*.cpp)) +CORE_CPP_SRCS := $(filter-out $(BOARD_CORE_CPP_SRCS_FILTER_OUT),$(CORE_CPP_SRCS)) CORE_OBJS := $(CORE_OBJS) $(addprefix build/core/,$(notdir $(CORE_CPP_SRCS:.cpp=.o))) -CORE_CORE_OBJS := build/core/RTAudio.o build/core/PRU.o build/core/RTAudioCommandLine.o build/core/I2c_Codec.o build/core/I2c_MultiTLVCodec.o build/core/I2c_MultiTdmCodec.o build/core/Spi_Codec.o build/core/math_runfast.o build/core/GPIOcontrol.o build/core/PruBinary.o build/core/board_detect.o build/core/DataFifo.o build/core/BelaContextFifo.o build/core/BelaContextSplitter.o build/core/MiscUtilities.o build/core/Mmap.o build/core/Mcasp.o build/core/PruManager.o +CORE_CORE_OBJS := build/core/RTAudio.o build/core/PRU.o build/core/RTAudioCommandLine.o build/core/I2c_Codec.o build/core/I2c_MultiTLVCodec.o build/core/I2c_MultiTdmCodec.o build/core/Spi_Codec.o build/core/math_runfast.o build/core/GPIOcontrol.o build/core/board_detect.o build/core/DataFifo.o build/core/BelaContextFifo.o build/core/BelaContextSplitter.o build/core/MiscUtilities.o build/core/Mmap.o build/core/Mcasp.o build/core/PruManager.o $(BOARD_CORE_CORE_OBJS) EXTRA_CORE_OBJS := $(filter-out $(CORE_CORE_OBJS), $(CORE_OBJS)) ALL_DEPS += $(addprefix build/core/,$(notdir $(CORE_CPP_SRCS:.cpp=.d))) From 637e2d4381b9346c3082c9d91700f968b3e8d6fc Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Thu, 29 Jul 2021 22:50:38 +0000 Subject: [PATCH 135/148] Makefile: build .out file via pasm+clpru when ENABLE_PRU_RPROC==1. --- Makefile | 56 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index e91148fcc..8d435f4bb 100644 --- a/Makefile +++ b/Makefile @@ -87,9 +87,9 @@ ifeq ($(RUN_WITH_PRU_BIN),true) ifndef PROJECT $(warning PROJECT is not defined, so RUN_WITH_PRU_BIN will be ignored) endif # ifndef PROJECT -COMMAND_LINE_OPTIONS := --pru-file $(BASE_DIR)/pru_rtaudio_irq.bin $(COMMAND_LINE_OPTIONS) -run: pru_rtaudio.bin -run: pru_rtaudio_irq.bin +COMMAND_LINE_OPTIONS := --pru-file build/pru/pru_rtaudio_irq.bin $(COMMAND_LINE_OPTIONS) +run: build/pru/pru_rtaudio.bin +run: build/pru/pru_rtaudio_irq.bin else build/core/PruBinary.o: build/pru/pru_rtaudio_bin.h build/pru/pru_rtaudio_irq_bin.h endif #ifeq($(RUN_WITH_PRU_BIN),true) @@ -312,17 +312,31 @@ ifeq (,$(AT)) endif ifeq (1,$(strip $(ENABLE_PRU_RPROC))) - firmwareBelaRProcNoMcaspIrq ?= $(BELA_DIR)/build/pru/pru_rtaudio_bin.out - firmwareBelaRProcMcaspIrq ?= $(BELA_DIR)/build/pru/pru_rtaudio_irq_bin.out + firmwareBelaRProcNoMcaspIrqRelative ?= build/pru/pru_rtaudio.out + firmwareBelaRProcMcaspIrqRelative ?= build/pru/pru_rtaudio_irq.out + firmwareBelaRProcNoMcaspIrq ?=$(BELA_DIR)/$(strip $(firmwareBelaRProcNoMcaspIrqRelative)) + firmwareBelaRProcMcaspIrq ?=$(BELA_DIR)/$(strip $(firmwareBelaRProcMcaspIrqRelative)) BOARD_CORE_LDLIBS = BOARD_CORE_CORE_OBJS = -else + RPROC_BUILD_DIR = build/pru/rproc + RPROC_RESOURCES_BASE=$(BELA_DIR)/resources/rproc-build + RPROC_TEMPLATE=$(RPROC_RESOURCES_BASE)/rproc-template.c + RPROC_TMP_FILE=$(RPROC_BUILD_DIR)/temp + RPROC_INCLUDE=$(RPROC_RESOURCES_BASE)/common + RPROC_INCLUDED_ASSEMBLY = $(RPROC_BUILD_DIR)/included_assembly.h + ifeq (1,$(IS_AM572x)) + RPROC_CMD:=$(RPROC_RESOURCES_BASE)/am57xx_pru.cmd + else + RPROC_CMD:=$(RPROC_RESOURCES_BASE)/am335x_pru.cmd + endif +else # ENABLE_PRU_RPROC is 0 BOARD_CORE_CPP_SRCS_FILTER_OUT := endif + ifeq (1,$(strip $(ENABLE_PRU_UIO))) BOARD_CORE_LDLIBS = -lprussdrv BOARD_CORE_CORE_OBJS = build/core/PruBinary.o -else +else # ENABLE_PRU_UIO is 0 BOARD_CORE_CPP_SRCS_FILTER_OUT := core/PruBinary.cpp endif @@ -410,6 +424,7 @@ CPP_OBJS := $(subst $(PROJECT_DIR),$(PROJECT_DIR)/build,$(CPP_SRCS:.cpp=.o)) BUILD_DIRS += $(dir $(C_OBJS)) BUILD_DIRS += $(dir $(CPP_OBJS)) +BUILD_DIRS += $(RPROC_BUILD_DIR) ALL_DEPS += $(addprefix $(PROJECT_DIR)/build/,$(notdir $(CPP_SRCS:.cpp=.d))) endif # $(PROJECT) #create build directories, should probably be conditional to PROJECT or li @@ -448,6 +463,9 @@ ALL_DEPS += ./build/core/default_main.d -include libraries/*/build/*.d # dependencies for each of the libraries' object files Bela: ## Builds the Bela program with all the optimizations +ifeq (1,$(strip $(ENABLE_PRU_RPROC))) +Bela: $(firmwareBelaRProcNoMcaspIrqRelative) $(firmwareBelaRProcMcaspIrqRelative) +endif Bela: $(OUTPUT_FILE) # all = build Bela @@ -496,19 +514,30 @@ ifeq (,$(SYNTAX_FLAG)) endif $(AT) echo ' ' -%.bin: pru/%.p +%.out: %.bin +ifeq (,$(SYNTAX_FLAG)) + $(AT) echo 'Building $< into $@...' + $(AT) prudis $< | sed 's/^\(.*\)$$/" \1\\n"/' > $(RPROC_INCLUDED_ASSEMBLY) + $(AT) clpru -fe $(RPROC_TMP_FILE).o $(RPROC_TEMPLATE) -v3 --endian=little --include_path=$(RPROC_BUILD_DIR) --include_path=$(RPROC_INCLUDE) --include_path=/usr/lib/ti/pru-software-support-package/include + $(AT) lnkpru -o $(RPROC_TMP_FILE).out $(RPROC_TMP_FILE).o --stack_size=0x0 --heap_size=0x0 -m $(RPROC_TMP_FILE).map $(RPROC_CMD) + $(AT) dd if=$< of=$(RPROC_TMP_FILE).out bs=1 obs=1 seek=52 conv=notrunc status=none + $(AT) mv $(RPROC_TMP_FILE).out $@ + $(AT) echo ' ...done' +endif + $(AT) echo ' ' + +build/pru/%.bin: pru/%.p ifeq (,$(SYNTAX_FLAG)) - $(AT) echo 'Building $<...' - $(AT) pasm -V2 -L -c -b "$<" > /dev/null + $(AT) echo 'Building $< into $@...' + $(AT) cd $(dir $@) && pasm -V2 -L -c -b $(BOARD_COMMON_FLAGS) $(BELA_DIR)/$< > /dev/null $(AT) echo ' ...done' endif $(AT) echo ' ' build/pru/%_bin.h: pru/%.p ifeq (,$(SYNTAX_FLAG)) - $(AT) echo 'Building $<...' - $(AT) pasm -V2 -L -c "$<" > /dev/null - $(AT) mv "$(@:build/pru/%=%)" build/pru/ + $(AT) echo 'Building $< into $@...' + $(AT) cd $(dir $@) && pasm -V2 -L -c $(BOARD_COMMON_FLAGS) $(BELA_DIR)/"$<" > /dev/null $(AT) echo ' ...done' endif $(AT) echo ' ' @@ -866,3 +895,4 @@ heavy-unzip-archive: stop .PHONY: all clean distclean help projectclean nostartup startup startuploop debug run runfg runscreen runscreenfg stopstartup stoprunning stop idestart idestop idestartup idenostartup ideconnect connect update checkupdate updateunsafe csoundstart scsynthstart scsynthstop scsynthstartup scsynthnostartup scsynthconnect lib c -include CustomMakefileBottom.in +.SECONDARY: build/pru/pru_rtaudio.bin build/pru/pru_rtaudio_irq.bin # prevents temporary files from being deleted) From b5b205da1a3e32f6dcff2ea71d1d2686a6538d20 Mon Sep 17 00:00:00 2001 From: Dhruva_Gole Date: Sat, 31 Jul 2021 18:22:39 +0530 Subject: [PATCH 136/148] Gpio: added support for AM572x --- core/Gpio.cpp | 53 ++++++++++++++++++++++++++++++++++++++------------ include/Gpio.h | 4 ++++ 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/core/Gpio.cpp b/core/Gpio.cpp index 5e0dc05c2..0b7d74516 100644 --- a/core/Gpio.cpp +++ b/core/Gpio.cpp @@ -1,13 +1,16 @@ #include "../include/Gpio.h" #include "GPIOcontrol.h" +#include +#include +#include +static const unsigned int kBitsPerGpioBank = 32; static const uint32_t GPIO_SIZE = 0x198; -static const uint32_t GPIO_ADDRESSES[4] = { - 0x44E07000, - 0x4804C000, - 0x481AC000, - 0x481AE000, -}; +#ifdef IS_AM572x +static const int kGpioBankIndexed = 1; +#else // IS_AM572x +static const int kGpioBankIndexed = 0; +#endif // IS_AM572x Gpio::Gpio() : pin(-1), gpio(nullptr) {} @@ -18,7 +21,11 @@ Gpio::~Gpio() } int Gpio::open(unsigned int newPin, Direction direction, bool unexport){ - if(newPin >= 128){ + unsigned int bank = getBankNumber(newPin); + uint32_t gpioBase; + try { + gpioBase = getBankAddress(bank); + } catch (std::exception&) { return -1; } pin = newPin; @@ -33,10 +40,8 @@ int Gpio::open(unsigned int newPin, Direction direction, bool unexport){ if(gpio_set_dir(pin, direction) < 0){ return -1; } - int bank = pin / 32; - pin = pin - bank * 32; - pinMask = 1 << pin; - uint32_t gpioBase = GPIO_ADDRESSES[bank]; + unsigned int bit = pin % kBitsPerGpioBank; + pinMask = 1 << bit; gpio = (uint32_t*)mmap.map(gpioBase, GPIO_SIZE); if(!gpio) return -2; @@ -58,7 +63,31 @@ void Gpio::close(){ pin = -1; } +uint32_t Gpio::getBankNumber(unsigned int pin) +{ + return pin / kBitsPerGpioBank + kGpioBankIndexed; +} + uint32_t Gpio::getBankAddress(unsigned int bank) { - return GPIO_ADDRESSES[bank]; + // GPIO_ADDRESSES is private to this function so that there is no ambiguity + // about whether it should be 0- or 1- indexed + static const std::vector GPIO_ADDRESSES = { + #ifdef IS_AM572x + 0x4AE10000, + 0x48055000, + 0x48057000, + 0x48059000, + 0x4805B000, + 0x4805D000, + 0x48051000, + 0x48053000, + #else // IS_AM572x + 0x44E07000, + 0x4804C000, + 0x481AC000, + 0x481AE000, + #endif // IS_AM572x + }; + return GPIO_ADDRESSES.at(bank - kGpioBankIndexed); } diff --git a/include/Gpio.h b/include/Gpio.h index 341336bc7..49de847ae 100644 --- a/include/Gpio.h +++ b/include/Gpio.h @@ -71,6 +71,10 @@ class Gpio{ return nullptr != gpio; } + /** + * A utility function to return the bank from a Gpio number. + */ + static uint32_t getBankNumber(unsigned int pin); /** * A utility function to return the base address of a Gpio bank. */ From 0131b068f8f9dc3edb31bde51faa6be3fbbc422b Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Sat, 31 Jul 2021 21:47:18 +0000 Subject: [PATCH 137/148] BBAI: updated most non-Bela GPIOs (except LED) --- core/PRU.cpp | 5 +++-- include/bela_hw_settings.h | 16 ++++++++++----- pru/pru_rtaudio.p | 40 ++++++++++++++++++++++++++------------ 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/core/PRU.cpp b/core/PRU.cpp index 74d02a06d..7aed6f254 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -21,6 +21,7 @@ #include "../include/Gpio.h" #include "../include/PruArmCommon.h" #include "../include/board_detect.h" +#include "../include/bela_hw_settings.h" #include #include @@ -196,8 +197,8 @@ const unsigned int belaMiniLedRed = 89; const unsigned int underrunLedDuration = 20000; const unsigned int saltSwitch1Gpio = 60; // P9_12 -const unsigned int PRU::kPruGPIODACSyncPin = 5; // GPIO0(5); P9-17 -const unsigned int PRU::kPruGPIOADCSyncPin = 48; // GPIO1(16); P9-15 +const unsigned int PRU::kPruGPIODACSyncPin = kSpiDacChipSelectPin; +const unsigned int PRU::kPruGPIOADCSyncPin = kSpiAdcChipSelectPin; #ifdef USE_NEON_FORMAT_CONVERSION // These four functions are written in assembly in FormatConvert.S diff --git a/include/bela_hw_settings.h b/include/bela_hw_settings.h index d0c8c96af..dfe13111b 100644 --- a/include/bela_hw_settings.h +++ b/include/bela_hw_settings.h @@ -1,12 +1,18 @@ #pragma once +const unsigned int codecI2cAddress = 0x18; // Address of TLV320AIC3104 codec #ifdef IS_AM572x // BBAI -const unsigned int codecI2cBus = 3; // Bus for TLV320AIC3104 codec +const unsigned int codecI2cBus = 3; // Bus for TLV320AIC3104 codec +const unsigned int kBelaCapeButtonPin = 111; //P9.27 +const unsigned int kAmplifierMutePin = 124; // P8.26 +const unsigned int kSpiDacChipSelectPin = 76; // P9.17 +const unsigned int kSpiAdcChipSelectPin = 209; // P9.15 #else // BBB -const unsigned int codecI2cBus = 2; // Bus for TLV320AIC3104 codec +const unsigned int codecI2cBus = 2; // Bus for TLV320AIC3104 codec +const unsigned int kBelaCapeButtonPin = 115; //P9.27 / P2.34 +const unsigned int kAmplifierMutePin = 61; // P8.26 / nothing on BelaMini +const unsigned int kSpiDacChipSelectPin = 5; // P9.17 used for ADC on BelaMini +const unsigned int kSpiAdcChipSelectPin = 48; // P9.15 unused on BelaMini #endif // IS_AM572x -const unsigned int codecI2cAddress = 0x18; // Address of TLV320AIC3104 codec -const unsigned int kBelaCapeButtonPin = 115; //P9.27 / P2.34 connected to The Button -const unsigned int kAmplifierMutePin = 61; // P8.26 controls amplifier mute #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 108) // first kernel we shipped with a different location of the spidevs diff --git a/pru/pru_rtaudio.p b/pru/pru_rtaudio.p index 20a15ffac..0cd8cb02d 100644 --- a/pru/pru_rtaudio.p +++ b/pru/pru_rtaudio.p @@ -41,8 +41,22 @@ #define SPI_CH1TX 0x4C #define SPI_CH1RX 0x50 +#ifdef IS_AM572x +#define GPIO1 0x4AE10000 +#define GPIO2 0x48055000 +#define GPIO3 0x48057000 +#define GPIO4 0x48059000 +#define GPIO5 0x4805B000 +#define GPIO6 0x4805D000 +#define GPIO7 0x48051000 +#define GPIO8 0x48053000 +#else // IS_AM572x #define GPIO0 0x44E07000 #define GPIO1 0x4804C000 +#define GPIO2 0x481AC000 +#define GPIO3 0x481AE000, +#endif // IS_AM572x + #define GPIO_CLEARDATAOUT 0x190 #define GPIO_SETDATAOUT 0x194 @@ -53,13 +67,13 @@ #define PRU_SYSTEM_EVENT_RTDM_WRITE_VALUE (1 << 5) | (PRU_SYSTEM_EVENT_RTDM - 16) #define C_ADC_DAC_MEM C24 // PRU0 mem -#ifdef DBOX_CAPE +#ifdef IS_AM572x +#define DAC_GPIO GPIO7 +#define DAC_CS_PIN (1<<17) // GPIO7:17 = P9 pin 17 +#else // IS_AM572x #define DAC_GPIO GPIO0 #define DAC_CS_PIN (1<<5) // GPIO0:5 = P9 pin 17 -#else /* DBOX_CAPE */ -#define DAC_GPIO GPIO1 -#define DAC_CS_PIN (1<<16) // GPIO1:16 = P9 pin 15 -#endif /* DBOX_CAPE */ +#endif // IS_AM572x #define DAC_TRM 0 // SPI transmit and receive #define DAC_WL 32 // Word length #define DAC_CLK_MODE 1 // SPI mode @@ -71,16 +85,16 @@ #define AD5668_DATA_OFFSET 4 #define AD5668_REF_OFFSET 0 -#ifdef DBOX_CAPE +#ifdef IS_AM572x +#define ADC_GPIO GPIO3 +#define ADC_CS_PIN (1<<12) // GPIO3:12 = P9 pin 15 +#else // IS_AM572x #define ADC_GPIO GPIO1 #define ADC_CS_PIN (1<<16) // GPIO1:16 = P9 pin 15 // for BELA_MINI, this is the same as DAC_CS_PIN, but the latter is disabled in DAC_WRITE #define ADC_GPIO_BELA_MINI GPIO0 #define ADC_CS_PIN_BELA_MINI (1<<5) // GPIO1:5 = P1 pin 6 -#else /* DBOX_CAPE */ -#define ADC_GPIO GPIO1 -#define ADC_CS_PIN (1<<17) // GPIO1:17 = P9 pin 23 -#endif /* DBOX_CAPE */ +#endif // IS_AM572x #define ADC_TRM 0 // SPI transmit and receive #define ADC_WL 16 // Word length @@ -278,8 +292,6 @@ //15 P8_30 59 0x8ec/0ec 89 gpio2[25] //generic GPIOs constants -//#define GPIO1 0x4804c000 -#define GPIO2 0x481ac000 //#define GPIO_CLEARDATAOUT 0x190 //SETDATAOUT is CLEARDATAOUT+4 #define GPIO_OE 0x134 #define GPIO_DATAIN 0x138 @@ -577,10 +589,12 @@ DAC_CHANNEL_REORDER_DONE: // Bring CS line low to write to ADC .macro ADC_CS_ASSERT +#ifndef IS_AM572x BELA_MINI_OR_JMP_TO BELA MOV r27, ADC_CS_PIN_BELA_MINI MOV r28, ADC_GPIO_BELA_MINI + GPIO_CLEARDATAOUT QBA DONE +#endif // IS_AM572x BELA: MOV r27, ADC_CS_PIN MOV r28, ADC_GPIO + GPIO_CLEARDATAOUT @@ -590,10 +604,12 @@ DONE: // Bring CS line high at end of ADC transaction .macro ADC_CS_UNASSERT +#ifndef IS_AM572x BELA_MINI_OR_JMP_TO BELA MOV r27, ADC_CS_PIN_BELA_MINI MOV r28, ADC_GPIO_BELA_MINI + GPIO_SETDATAOUT QBA DONE +#endif // IS_AM572x BELA: MOV r27, ADC_CS_PIN MOV r28, ADC_GPIO + GPIO_SETDATAOUT From 26d65f979d4eeb732f8ca5665a0e7a8bf3ecc8e9 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Sat, 31 Jul 2021 23:08:03 +0000 Subject: [PATCH 138/148] Gpio: added getMask() --- core/Gpio.cpp | 9 +++++++-- include/Gpio.h | 4 ++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/core/Gpio.cpp b/core/Gpio.cpp index 0b7d74516..338a83c67 100644 --- a/core/Gpio.cpp +++ b/core/Gpio.cpp @@ -40,8 +40,7 @@ int Gpio::open(unsigned int newPin, Direction direction, bool unexport){ if(gpio_set_dir(pin, direction) < 0){ return -1; } - unsigned int bit = pin % kBitsPerGpioBank; - pinMask = 1 << bit; + pinMask = getMask(pin); gpio = (uint32_t*)mmap.map(gpioBase, GPIO_SIZE); if(!gpio) return -2; @@ -63,6 +62,12 @@ void Gpio::close(){ pin = -1; } +uint32_t Gpio::getMask(unsigned int pin) +{ + unsigned int bit = pin % kBitsPerGpioBank; + return 1 << bit; +} + uint32_t Gpio::getBankNumber(unsigned int pin) { return pin / kBitsPerGpioBank + kGpioBankIndexed; diff --git a/include/Gpio.h b/include/Gpio.h index 49de847ae..ff6e8db1d 100644 --- a/include/Gpio.h +++ b/include/Gpio.h @@ -71,6 +71,10 @@ class Gpio{ return nullptr != gpio; } + /** + * A utility function to return the mask from a Gpio number. + */ + static uint32_t getMask(unsigned int pin); /** * A utility function to return the bank from a Gpio number. */ From a3b3818573c7490fc65a257ed246670cbbb821de Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Sat, 31 Jul 2021 23:09:22 +0000 Subject: [PATCH 139/148] PRU: de-hard-coded UserLed name, number and triggers. Also supports BBAI --- core/PRU.cpp | 14 +++++++------- include/bela_hw_settings.h | 14 ++++++++++++-- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/core/PRU.cpp b/core/PRU.cpp index 7aed6f254..90675f5a5 100644 --- a/core/PRU.cpp +++ b/core/PRU.cpp @@ -188,8 +188,8 @@ class PruMemory static unsigned int* gDigitalPins = NULL; -const uint32_t userLed3GpioBase = Gpio::getBankAddress(1); -const uint32_t userLed3GpioPinMask = 1 << 24; +const uint32_t userLedGpioBase = Gpio::getBankAddress(Gpio::getBankNumber(kUserLedGpioPin)); +const uint32_t userLedGpioPinMask = Gpio::getMask(kUserLedGpioPin); const unsigned int belaMiniLedBlue = 87; const uint32_t belaMiniLedBlueGpioBase = Gpio::getBankAddress(2); // GPIO2(23) is BelaMini LED blue const uint32_t belaMiniLedBlueGpioPinMask = 1 << 23; @@ -316,7 +316,7 @@ int PRU::prepareGPIO(int include_led) } else { // Using BeagleBone's USR3 LED // Turn off system function for LED3 so it can be reused by PRU - led_set_trigger(3, "none"); + led_set_trigger(kUserLedNumber, "none"); led_enabled = true; } } @@ -355,10 +355,10 @@ void PRU::cleanupGPIO() //using on-board LED gpio_unexport(belaMiniLedBlue); } else { - // Set LED back to default eMMC status + // Set LED back to default status // TODO: make it go back to its actual value before this program, // rather than the system default - led_set_trigger(3, "mmc1"); + led_set_trigger(kUserLedNumber, kUserLedDefaultTrigger); } } gpio_enabled = false; @@ -630,8 +630,8 @@ void PRU::initialisePruCommon(const McaspRegisters& mcaspRegisters) pru_buffer_comm[PRU_COMM_LED_ADDRESS] = belaMiniLedBlueGpioBase; pru_buffer_comm[PRU_COMM_LED_PIN_MASK] = belaMiniLedBlueGpioPinMask; } else { - pru_buffer_comm[PRU_COMM_LED_ADDRESS] = userLed3GpioBase; - pru_buffer_comm[PRU_COMM_LED_PIN_MASK] = userLed3GpioPinMask; + pru_buffer_comm[PRU_COMM_LED_ADDRESS] = userLedGpioBase; + pru_buffer_comm[PRU_COMM_LED_PIN_MASK] = userLedGpioPinMask; } } else { diff --git a/include/bela_hw_settings.h b/include/bela_hw_settings.h index dfe13111b..c9e457003 100644 --- a/include/bela_hw_settings.h +++ b/include/bela_hw_settings.h @@ -1,17 +1,27 @@ #pragma once const unsigned int codecI2cAddress = 0x18; // Address of TLV320AIC3104 codec -#ifdef IS_AM572x // BBAI +#ifdef IS_AM572x +// This assumes BBAI const unsigned int codecI2cBus = 3; // Bus for TLV320AIC3104 codec const unsigned int kBelaCapeButtonPin = 111; //P9.27 const unsigned int kAmplifierMutePin = 124; // P8.26 const unsigned int kSpiDacChipSelectPin = 76; // P9.17 const unsigned int kSpiAdcChipSelectPin = 209; // P9.15 -#else // BBB +// below are for user LED D8 on BBAI +const unsigned int kUserLedGpioPin = 71; +const unsigned int kUserLedNumber = 4; +const char kUserLedDefaultTrigger[] = "netdev"; +#else // IS_AM572x +// This assumes BBB/BBG/PB const unsigned int codecI2cBus = 2; // Bus for TLV320AIC3104 codec const unsigned int kBelaCapeButtonPin = 115; //P9.27 / P2.34 const unsigned int kAmplifierMutePin = 61; // P8.26 / nothing on BelaMini const unsigned int kSpiDacChipSelectPin = 5; // P9.17 used for ADC on BelaMini const unsigned int kSpiAdcChipSelectPin = 48; // P9.15 unused on BelaMini +// below are for user LED USR3 +const unsigned int kUserLedGpioPin = 71; +const unsigned int kUserLedNumber = 3; +const char kUserLedDefaultTrigger[] = "mmc1"; #endif // IS_AM572x #include From 5e5a042fe353bc1bedd87878655c5044012011ae Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Sat, 31 Jul 2021 23:28:29 +0000 Subject: [PATCH 140/148] pru: NIT: fixed comment --- pru/pru_rtaudio.p | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pru/pru_rtaudio.p b/pru/pru_rtaudio.p index 0cd8cb02d..f30c77c58 100644 --- a/pru/pru_rtaudio.p +++ b/pru/pru_rtaudio.p @@ -393,7 +393,7 @@ SET_GPIO_BITS_0_DONE: // r2 is now unused //GPIO2-start -//r3 will hold GPIO1_OE +//r3 will hold GPIO2_OE //load current status of GPIO_OE in r3 MOV r3, GPIO2 | GPIO_OE //it takes 200ns to go through the next instructions From 38cc7fe18a181776820ad88d23b60983fa9c9e80 Mon Sep 17 00:00:00 2001 From: Dhruva_Gole Date: Sun, 1 Aug 2021 21:31:56 +0530 Subject: [PATCH 141/148] pru_rtaudio.p: fix McSPI BASE for BBAI --- pru/pru_rtaudio.p | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pru/pru_rtaudio.p b/pru/pru_rtaudio.p index f30c77c58..4ac84b10a 100644 --- a/pru/pru_rtaudio.p +++ b/pru/pru_rtaudio.p @@ -9,18 +9,19 @@ #define CLOCK_BASE 0x4A005000 #define CLOCK_MCASP0 0x550 #define CLOCK_MCASP_VALUE 0x7000002 +#define CLOCK_SPI0 0x47F8 #else // IS_AM572x #define CLOCK_BASE 0x44E00000 #define CLOCK_MCASP0 0x34 #define CLOCK_MCASP_VALUE 0x30002 // should probably be just 0x2 -#endif // IS_AM572x #define CLOCK_SPI0 0x4C +#endif // IS_AM572x #define CLOCK_SPI1 0x50 #define CLOCK_L4LS 0x60 #ifdef IS_AM572x -#define SPI0_BASE 0x4809A100 -#define SPI1_BASE 0x480B8100 +#define SPI0_BASE 0x4809A100 // McSPI2_REVISION AM572x +#define SPI1_BASE 0x4809A100 #else #define SPI0_BASE 0x48030100 #define SPI1_BASE 0x481A0100 From 8f2b4b67ca14c8bbc5f47305ee5f43c7c109da65 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Sun, 1 Aug 2021 01:51:58 +0000 Subject: [PATCH 142/148] BBAI: added more than half of the Bela digitals. Currently using only GPIO4 and GPIO6 in the PRU code. More pins are on GPIO3 and GPIO5 and require significant extra work on the PRU side --- include/digital_gpio_mapping.h | 20 ++++++++++++ pru/pru_rtaudio.p | 58 +++++++++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/include/digital_gpio_mapping.h b/include/digital_gpio_mapping.h index 59db6e2b3..956538b75 100644 --- a/include/digital_gpio_mapping.h +++ b/include/digital_gpio_mapping.h @@ -34,6 +34,25 @@ enum enum { +#ifdef IS_AM572x + // these are for BeagleBoneAI + P8_07_GPIO_NO = 165, + P8_08_GPIO_NO = 166, + P8_09_GPIO_NO = 178, + P8_10_GPIO_NO = 164, + P8_11_GPIO_NO = 75, + P8_12_GPIO_NO = 74, + P9_12_GPIO_NO = 128, + P9_14_GPIO_NO = 121, + P8_15_GPIO_NO = 99, + P8_16_GPIO_NO = 125, + P9_16_GPIO_NO = 122, + P8_18_GPIO_NO = 105, + P8_27_GPIO_NO = 119, + P8_28_GPIO_NO = 115, + P8_29_GPIO_NO = 118, + P8_30_GPIO_NO = 116, +#else // IS_AM572x // these are for BeagleBone (Everything else) P8_07_GPIO_NO = 66, P8_08_GPIO_NO = 67, @@ -51,6 +70,7 @@ enum P8_28_GPIO_NO = 88, P8_29_GPIO_NO = 87, P8_30_GPIO_NO = 89, +#endif // IS_AM572x }; //mapping pin headers to bits in the digital word. diff --git a/pru/pru_rtaudio.p b/pru/pru_rtaudio.p index 4ac84b10a..e06543276 100644 --- a/pru/pru_rtaudio.p +++ b/pru/pru_rtaudio.p @@ -347,7 +347,37 @@ DIGITAL: //r27 is now the input word passed in render(), one word per frame //[31:16]: data(1=high, 0=low), [15:0]: direction (0=output, 1=input) ) - +#ifdef IS_AM572x +// same code as below with different mappings and without comments for brevity +// GPIO6-start + MOV r2, GPIO6 | GPIO_OE + LBBO r2, r2, 0, 4 + MOV r8, 0 + MOV r7, 0 + SET_GPIO_BITS r2, r8, r7, 5, 0, r27 + SET_GPIO_BITS r2, r8, r7, 6, 1, r27 + SET_GPIO_BITS r2, r8, r7, 18, 2, r27 + SET_GPIO_BITS r2, r8, r7, 4, 3, r27 + MOV r3, GPIO6 | GPIO_OE + SBBO r2, r3, 0, 4 +//GPIO6-end +//GPIO4-start + MOV r3, GPIO4 | GPIO_OE + LBBO r3, r3, 0, 4 + MOV r5, 0 + MOV r4, 0 + SET_GPIO_BITS r3, r5, r4, 3, 8, r27 + SET_GPIO_BITS r3, r5, r4, 29, 9, r27 + SET_GPIO_BITS r3, r5, r4, 26, 10, r27 + SET_GPIO_BITS r3, r5, r4, 9, 11, r27 + SET_GPIO_BITS r3, r5, r4, 23, 12, r27 + SET_GPIO_BITS r3, r5, r4, 19, 13, r27 + SET_GPIO_BITS r3, r5, r4, 22, 14, r27 + SET_GPIO_BITS r3, r5, r4, 20, 15, r27 + MOV r2, GPIO4 | GPIO_OE //use r2 as a temp registerp + SBBO r3, r2, 0, 4 //takes two cycles (10ns) +//GPIO4-end +#else // IS_AM572x //Preparing the gpio_oe, gpio_cleardataout and gpio_setdataout for each module //r2 will hold GPIO1_OE //load current status of GPIO_OE in r2 @@ -428,12 +458,37 @@ SET_GPIO_BITS_1_DONE: SBBO r3, r2, 0, 4 //takes two cycles (10ns) //GPIO2-end //r3 is now unused +#endif // IS_AM572x QBA START_INTERMEDIATE_DONE START_INTERMEDIATE: // intermediate step to jump to START QBA START START_INTERMEDIATE_DONE: +#ifdef IS_AM572x + MOV r2, GPIO6 | GPIO_DATAIN + MOV r3, GPIO4 | GPIO_DATAIN + LBBO r2, r2, 0, 4 + LBBO r3, r3, 0, 4 +//GPIO6 + READ_GPIO_BITS r2, 5, 0, r27 + READ_GPIO_BITS r2, 6, 1, r27 + READ_GPIO_BITS r2, 18, 2, r27 + READ_GPIO_BITS r2, 4, 3, r27 +//GPIO4 + READ_GPIO_BITS r3, 3, 8, r27 + READ_GPIO_BITS r3, 29, 9, r27 + READ_GPIO_BITS r3, 26, 10, r27 + READ_GPIO_BITS r3, 9, 11, r27 + READ_GPIO_BITS r3, 23, 12, r27 + READ_GPIO_BITS r3, 19, 13, r27 + READ_GPIO_BITS r3, 22, 14, r27 + READ_GPIO_BITS r3, 20, 15, r27 + MOV r2, GPIO6 | GPIO_CLEARDATAOUT + MOV r3, GPIO4 | GPIO_CLEARDATAOUT + SBBO r7, r2, 0, 8 + SBBO r4, r3, 0, 8 +#else // IS_AM572x //load current inputs in r2, r3 //r2 will contain GPIO1_DATAIN //r3 will contain GPIO2_DATAIN @@ -502,6 +557,7 @@ READ_GPIO_BITS_DONE: //reversing the order of the two lines above will swap the performances between the GPIO modules //i.e.: the first line will always take 145ns/185ns and the second one will always take 95ns/130ns, //regardless of whether the order is gpio1-gpio2 or gpio2-gpio1 +#endif // IS_AM572x JMP r28.w0 // go back to ADC_WRITE_AND_PROCESS_GPIO .macro HANG //useful for debugging From 551beb62c9c0ad4fdf6848736d9ecc9291da29bf Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Sun, 1 Aug 2021 02:07:38 +0000 Subject: [PATCH 143/148] pru: added support for SPI analog ADC/DAC on BBAI (data lines are swapped with respect to BBB) --- pru/pru_rtaudio.p | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pru/pru_rtaudio.p b/pru/pru_rtaudio.p index e06543276..365935d4e 100644 --- a/pru/pru_rtaudio.p +++ b/pru/pru_rtaudio.p @@ -79,7 +79,11 @@ #define DAC_WL 32 // Word length #define DAC_CLK_MODE 1 // SPI mode #define DAC_CLK_DIV 1 // Clock divider (48MHz / 2^n) -#define DAC_DPE 1 // d0 = receive, d1 = transmit +#ifdef IS_AM572x +#define SPI_DPE_IS 0x6 // d1 = receive, d0 = transmit, input select d1 +#else // IS_AM572x +#define SPI_DPE_IS 0x1 // d0 = receive, d1 = transmit, input select d0 +#endif // IS_AM572x #define AD5668_COMMAND_OFFSET 24 #define AD5668_ADDRESS_OFFSET 20 @@ -101,7 +105,6 @@ #define ADC_WL 16 // Word length #define ADC_CLK_MODE 0 // SPI mode #define ADC_CLK_DIV 1 // Clock divider (48MHz / 2^n) -#define ADC_DPE 1 // d0 = receive, d1 = transmit #define AD7699_CFG_MASK 0xF120 // Mask for config update, unipolar, full BW #define AD7699_CHANNEL_OFFSET 9 // 7 bits offset of a 14-bit left-justified word @@ -943,11 +946,11 @@ SPI_WAIT_RESET: SBBO r2, reg_spi_addr, SPI_MODULCTRL, 4 // Configure CH0 for DAC - MOV r2, (3 << 27) | (DAC_DPE << 16) | (DAC_TRM << 12) | ((DAC_WL - 1) << 7) | (DAC_CLK_DIV << 2) | DAC_CLK_MODE | (1 << 6) + MOV r2, (3 << 27) | (SPI_DPE_IS << 16) | (DAC_TRM << 12) | ((DAC_WL - 1) << 7) | (DAC_CLK_DIV << 2) | DAC_CLK_MODE | (1 << 6) SBBO r2, reg_spi_addr, SPI_CH0CONF, 4 // Configure CH1 for ADC - MOV r2, (3 << 27) | (ADC_DPE << 16) | (ADC_TRM << 12) | ((ADC_WL - 1) << 7) | (ADC_CLK_DIV << 2) | ADC_CLK_MODE + MOV r2, (3 << 27) | (SPI_DPE_IS << 16) | (ADC_TRM << 12) | ((ADC_WL - 1) << 7) | (ADC_CLK_DIV << 2) | ADC_CLK_MODE SBBO r2, reg_spi_addr, SPI_CH1CONF, 4 // Turn on SPI channels From ae5264680f71cab16ae54ef136344dd1f407c153 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 2 Aug 2021 09:06:57 +0000 Subject: [PATCH 144/148] pru: NIT: assigned real names to AM572x's MCASP and SPI peripherals. Verified no changes in the built pru file --- pru/pru_rtaudio.p | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/pru/pru_rtaudio.p b/pru/pru_rtaudio.p index 365935d4e..7d8397f03 100644 --- a/pru/pru_rtaudio.p +++ b/pru/pru_rtaudio.p @@ -7,27 +7,32 @@ #ifdef IS_AM572x #define CLOCK_BASE 0x4A005000 -#define CLOCK_MCASP0 0x550 +#define CLOCK_MCASP1 0x550 #define CLOCK_MCASP_VALUE 0x7000002 -#define CLOCK_SPI0 0x47F8 +#define CLOCK_SPI2 0x47F8 +#define SPI2_BASE 0x4809A100 +#define MCASP1_BASE 0x48460000 #else // IS_AM572x #define CLOCK_BASE 0x44E00000 #define CLOCK_MCASP0 0x34 #define CLOCK_MCASP_VALUE 0x30002 // should probably be just 0x2 #define CLOCK_SPI0 0x4C +#define SPI0_BASE 0x48030100 +#define MCASP0_BASE 0x48038000 #endif // IS_AM572x -#define CLOCK_SPI1 0x50 -#define CLOCK_L4LS 0x60 #ifdef IS_AM572x -#define SPI0_BASE 0x4809A100 // McSPI2_REVISION AM572x -#define SPI1_BASE 0x4809A100 +#define SPI_BASE SPI2_BASE +#define CLOCK_SPI CLOCK_SPI2 +#define MCASP_BASE MCASP1_BASE +#define CLOCK_MCASP CLOCK_MCASP1 #else -#define SPI0_BASE 0x48030100 -#define SPI1_BASE 0x481A0100 -#endif #define SPI_BASE SPI0_BASE - +#define CLOCK_SPI CLOCK_SPI0 +#define MCASP_BASE MCASP0_BASE +#define CLOCK_MCASP CLOCK_MCASP0 +#endif + #define SPI_SYSCONFIG 0x10 #define SPI_SYSSTATUS 0x14 #define SPI_MODULCTRL 0x28 @@ -112,13 +117,6 @@ #define SHARED_COMM_MEM_BASE 0x00010000 // Location where comm flags are written -// General constants for McASP peripherals (used for audio codec) -#ifdef IS_AM572x -#define MCASP0_BASE 0x48460000 // pg 6118 of AM57x Manual, it actually is MCASP1 but temporarily keeping as 0 for testing ease -#else -#define MCASP0_BASE 0x48038000 -#endif - #define MCASP_PWRIDLESYSCONFIG 0x04 #define MCASP_PFUNC 0x10 #define MCASP_PDIR 0x14 @@ -195,7 +193,6 @@ #define MCASP_RSTAT_RDATA_BIT 5 // Bit to test for receive ready // Constants used for this particular audio setup -#define MCASP_BASE MCASP0_BASE #ifdef DBOX_CAPE #ifdef IS_AM572x #define MCASP_SRCTL_X MCASP_SRCTL11 // Ser. 11 is transmitter @@ -925,7 +922,7 @@ SPI_NUM_CHANNELS_DONE: // Init SPI clock MOV r2, 0x02 - MOV r3, CLOCK_BASE + CLOCK_SPI0 + MOV r3, CLOCK_BASE + CLOCK_SPI SBBO r2, r3, 0, 4 // Reset SPI and wait for finish @@ -980,7 +977,7 @@ SPI_INIT_DONE: // enable MCASP interface clock in PRCM MOV r2, CLOCK_MCASP_VALUE - MOV r3, CLOCK_BASE + CLOCK_MCASP0 + MOV r3, CLOCK_BASE + CLOCK_MCASP SBBO r2, r3, 0, 4 // we need to wait for a few cycles after enabling the clock in order for From 8b1e0e6776ca6676bc27459d1c7b483a058dabf4 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 2 Aug 2021 11:59:48 +0000 Subject: [PATCH 145/148] pru: factored out board-specific constants to board_specific.h Verified that the built pru file remains unchanged. --- Makefile | 4 +- pru/board_specific.h | 100 +++++++++++++++++++++++++++++++++++++++ pru/pru_rtaudio.p | 109 ++----------------------------------------- 3 files changed, 106 insertions(+), 107 deletions(-) create mode 100644 pru/board_specific.h diff --git a/Makefile b/Makefile index 8d435f4bb..e7c7535b6 100644 --- a/Makefile +++ b/Makefile @@ -526,7 +526,7 @@ ifeq (,$(SYNTAX_FLAG)) endif $(AT) echo ' ' -build/pru/%.bin: pru/%.p +build/pru/%.bin: pru/%.p include/PruArmCommon.h pru/board_specific.h ifeq (,$(SYNTAX_FLAG)) $(AT) echo 'Building $< into $@...' $(AT) cd $(dir $@) && pasm -V2 -L -c -b $(BOARD_COMMON_FLAGS) $(BELA_DIR)/$< > /dev/null @@ -534,7 +534,7 @@ ifeq (,$(SYNTAX_FLAG)) endif $(AT) echo ' ' -build/pru/%_bin.h: pru/%.p +build/pru/%_bin.h: pru/%.p include/PruArmCommon.h pru/board_specific.h ifeq (,$(SYNTAX_FLAG)) $(AT) echo 'Building $< into $@...' $(AT) cd $(dir $@) && pasm -V2 -L -c $(BOARD_COMMON_FLAGS) $(BELA_DIR)/"$<" > /dev/null diff --git a/pru/board_specific.h b/pru/board_specific.h new file mode 100644 index 000000000..07308bfb4 --- /dev/null +++ b/pru/board_specific.h @@ -0,0 +1,100 @@ +// board-specific peripheral and pins definitions + +//#define AUDIO_CAPE // as in: CircuitCo Audio Cape (I _think_: long untested) + +#ifdef IS_AM572x + +#define CLOCK_BASE 0x4A005000 +#define CLOCK_MCASP1 0x550 +#define CLOCK_MCASP_VALUE 0x7000002 +#define CLOCK_SPI2 0x47F8 +#define SPI2_BASE 0x4809A100 +#define MCASP1_BASE 0x48460000 +#define MCASP1_DATAPORT 0x45800000 +#define GPIO1 0x4AE10000 +#define GPIO2 0x48055000 +#define GPIO3 0x48057000 +#define GPIO4 0x48059000 +#define GPIO5 0x4805B000 +#define GPIO6 0x4805D000 +#define GPIO7 0x48051000 +#define GPIO8 0x48053000 + +#else // IS_AM572x + +#define CLOCK_BASE 0x44E00000 +#define CLOCK_MCASP0 0x34 +#define CLOCK_MCASP_VALUE 0x30002 // should probably be just 0x2 +#define CLOCK_SPI0 0x4C +#define SPI0_BASE 0x48030100 +#define MCASP0_BASE 0x48038000 +#define MCASP0_DATAPORT 0x46000000 +#define GPIO0 0x44E07000 +#define GPIO1 0x4804C000 +#define GPIO2 0x481AC000 +#define GPIO3 0x481AE000, + +#endif // IS_AM572x + +// below we select the peripherals and pins we are actually using +#ifdef IS_AM572x + +#define SPI_BASE SPI2_BASE +#define CLOCK_SPI CLOCK_SPI2 +#define MCASP_BASE MCASP1_BASE +#define CLOCK_MCASP CLOCK_MCASP1 +#define MCASP_DATAPORT MCASP1_DATAPORT +#define DAC_GPIO GPIO7 +#define DAC_CS_PIN (1<<17) // GPIO7:17 = P9 pin 17 +#define SPI_DPE_IS 0x6 // d1 = receive, d0 = transmit, input select d1 +#define ADC_GPIO GPIO3 +#define ADC_CS_PIN (1<<12) // GPIO3:12 = P9 pin 15 + +// MCASP settings below are ignored by pru_rtaudio_irq when in BELA_GENERIC_TDM mode +#define MCASP_SRCTL_X MCASP_SRCTL11 // Ser. 11 is transmitter +#define MCASP_SRCTL_R MCASP_SRCTL10 // Ser. 10 is receiver +#define MCASP_XBUF MCASP_XBUF11 +#define MCASP_RBUF MCASP_RBUF10 +#define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 11) // AHCLKX and AXR2 outputs + +#else // IS_AM572x + +#define SPI_BASE SPI0_BASE +#define CLOCK_SPI CLOCK_SPI0 +#define MCASP_BASE MCASP0_BASE +#define CLOCK_MCASP CLOCK_MCASP0 +#define MCASP_DATAPORT MCASP0_DATAPORT +#define DAC_GPIO GPIO0 +#define DAC_CS_PIN (1<<5) // GPIO0:5 = P9 pin 17 +#define SPI_DPE_IS 0x1 // d0 = receive, d1 = transmit, input select d0 +#define ADC_GPIO GPIO1 +#define ADC_CS_PIN (1<<16) // GPIO1:16 = P9 pin 15 +// for BELA_MINI, this is the same as DAC_CS_PIN, but the latter is disabled in DAC_WRITE +#define ADC_GPIO_BELA_MINI GPIO0 +#define ADC_CS_PIN_BELA_MINI (1<<5) // GPIO1:5 = P1 pin 6 + +// MCASP settings below are ignored by pru_rtaudio_irq when in BELA_GENERIC_TDM mode +#define MCASP_SRCTL_X MCASP_SRCTL2 // Ser. 2 is transmitter +#define MCASP_SRCTL_R MCASP_SRCTL0 // Ser. 0 is receiver +#define MCASP_XBUF MCASP_XBUF2 +#define MCASP_RBUF MCASP_RBUF0 +#define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 2) // AHCLKX and AXR2 outputs + +#endif // IS_AM572x + +#ifdef AUDIO_CAPE +#ifdef IS_AM572x +#error You should define appropriate values for AUDIO_CAPE +#else // IS_AM572x +#undef MCASP_SRCTL_X +#undef MCASP_SRCTL_R +#undef MCASP_XBUF +#undef MCASP_RBUF +#undef MCASP_OUTPUT_PINS +#define MCASP_SRCTL_X MCASP_SRCTL3 // Ser. 3 is transmitter +#define MCASP_SRCTL_R MCASP_SRCTL2 // Ser. 2 is receiver +#define MCASP_XBUF MCASP_XBUF3 +#define MCASP_RBUF MCASP_RBUF2 +#define MCASP_OUTPUT_PINS (1 << 3) // Which pins are outputs +#endif // IS_AM572x +#endif // AUDIO_CAPE diff --git a/pru/pru_rtaudio.p b/pru/pru_rtaudio.p index 7d8397f03..7b6f04d9a 100644 --- a/pru/pru_rtaudio.p +++ b/pru/pru_rtaudio.p @@ -2,36 +2,7 @@ .entrypoint START #include "../include/PruArmCommon.h" - -#define DBOX_CAPE // Define this to use new cape hardware - -#ifdef IS_AM572x -#define CLOCK_BASE 0x4A005000 -#define CLOCK_MCASP1 0x550 -#define CLOCK_MCASP_VALUE 0x7000002 -#define CLOCK_SPI2 0x47F8 -#define SPI2_BASE 0x4809A100 -#define MCASP1_BASE 0x48460000 -#else // IS_AM572x -#define CLOCK_BASE 0x44E00000 -#define CLOCK_MCASP0 0x34 -#define CLOCK_MCASP_VALUE 0x30002 // should probably be just 0x2 -#define CLOCK_SPI0 0x4C -#define SPI0_BASE 0x48030100 -#define MCASP0_BASE 0x48038000 -#endif // IS_AM572x - -#ifdef IS_AM572x -#define SPI_BASE SPI2_BASE -#define CLOCK_SPI CLOCK_SPI2 -#define MCASP_BASE MCASP1_BASE -#define CLOCK_MCASP CLOCK_MCASP1 -#else -#define SPI_BASE SPI0_BASE -#define CLOCK_SPI CLOCK_SPI0 -#define MCASP_BASE MCASP0_BASE -#define CLOCK_MCASP CLOCK_MCASP0 -#endif +#include "board_specific.h" #define SPI_SYSCONFIG 0x10 #define SPI_SYSSTATUS 0x14 @@ -47,22 +18,8 @@ #define SPI_CH1TX 0x4C #define SPI_CH1RX 0x50 -#ifdef IS_AM572x -#define GPIO1 0x4AE10000 -#define GPIO2 0x48055000 -#define GPIO3 0x48057000 -#define GPIO4 0x48059000 -#define GPIO5 0x4805B000 -#define GPIO6 0x4805D000 -#define GPIO7 0x48051000 -#define GPIO8 0x48053000 -#else // IS_AM572x -#define GPIO0 0x44E07000 -#define GPIO1 0x4804C000 -#define GPIO2 0x481AC000 -#define GPIO3 0x481AE000, -#endif // IS_AM572x - +#define GPIO_OE 0x134 +#define GPIO_DATAIN 0x138 #define GPIO_CLEARDATAOUT 0x190 #define GPIO_SETDATAOUT 0x194 @@ -73,39 +30,16 @@ #define PRU_SYSTEM_EVENT_RTDM_WRITE_VALUE (1 << 5) | (PRU_SYSTEM_EVENT_RTDM - 16) #define C_ADC_DAC_MEM C24 // PRU0 mem -#ifdef IS_AM572x -#define DAC_GPIO GPIO7 -#define DAC_CS_PIN (1<<17) // GPIO7:17 = P9 pin 17 -#else // IS_AM572x -#define DAC_GPIO GPIO0 -#define DAC_CS_PIN (1<<5) // GPIO0:5 = P9 pin 17 -#endif // IS_AM572x #define DAC_TRM 0 // SPI transmit and receive #define DAC_WL 32 // Word length #define DAC_CLK_MODE 1 // SPI mode #define DAC_CLK_DIV 1 // Clock divider (48MHz / 2^n) -#ifdef IS_AM572x -#define SPI_DPE_IS 0x6 // d1 = receive, d0 = transmit, input select d1 -#else // IS_AM572x -#define SPI_DPE_IS 0x1 // d0 = receive, d1 = transmit, input select d0 -#endif // IS_AM572x #define AD5668_COMMAND_OFFSET 24 #define AD5668_ADDRESS_OFFSET 20 #define AD5668_DATA_OFFSET 4 #define AD5668_REF_OFFSET 0 -#ifdef IS_AM572x -#define ADC_GPIO GPIO3 -#define ADC_CS_PIN (1<<12) // GPIO3:12 = P9 pin 15 -#else // IS_AM572x -#define ADC_GPIO GPIO1 -#define ADC_CS_PIN (1<<16) // GPIO1:16 = P9 pin 15 -// for BELA_MINI, this is the same as DAC_CS_PIN, but the latter is disabled in DAC_WRITE -#define ADC_GPIO_BELA_MINI GPIO0 -#define ADC_CS_PIN_BELA_MINI (1<<5) // GPIO1:5 = P1 pin 6 -#endif // IS_AM572x - #define ADC_TRM 0 // SPI transmit and receive #define ADC_WL 16 // Word length #define ADC_CLK_MODE 0 // SPI mode @@ -191,42 +125,12 @@ #define MCASP_XSTAT_XUNDRN_BIT 0 // Bit to test if there was an underrun #define MCASP_XSTAT_XDATA_BIT 5 // Bit to test for transmit ready #define MCASP_RSTAT_RDATA_BIT 5 // Bit to test for receive ready - -// Constants used for this particular audio setup -#ifdef DBOX_CAPE -#ifdef IS_AM572x -#define MCASP_SRCTL_X MCASP_SRCTL11 // Ser. 11 is transmitter -#define MCASP_SRCTL_R MCASP_SRCTL10 // Ser. 10 is receiver -#define MCASP_XBUF MCASP_XBUF11 -#define MCASP_RBUF MCASP_RBUF10 -#else // IS_AM572x -#define MCASP_SRCTL_X MCASP_SRCTL2 // Ser. 2 is transmitter -#define MCASP_SRCTL_R MCASP_SRCTL0 // Ser. 0 is receiver -#define MCASP_XBUF MCASP_XBUF2 -#define MCASP_RBUF MCASP_RBUF0 -#endif // IS_AM572x -#else -#define MCASP_SRCTL_X MCASP_SRCTL3 // Ser. 3 is transmitter -#define MCASP_SRCTL_R MCASP_SRCTL2 // Ser. 2 is receiver -#define MCASP_XBUF MCASP_XBUF3 -#define MCASP_RBUF MCASP_RBUF2 -#endif - + #define MCASP_PIN_AFSX (1 << 28) #define MCASP_PIN_AHCLKX (1 << 27) #define MCASP_PIN_ACLKX (1 << 26) #define MCASP_PIN_AMUTE (1 << 25) // Also, 0 to 3 are XFR0 to XFR3 -#ifdef DBOX_CAPE -#ifdef IS_AM572x -#define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 11) // AHCLKX and AXR2 outputs -#else // IS_AM572x -#define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 2) // AHCLKX and AXR2 outputs -#endif // IS_AM572x -#else -#define MCASP_OUTPUT_PINS (1 << 3) // Which pins are outputs -#endif - #define MCASP_DATA_MASK 0xFFFF // 16 bit data #define MCASP_DATA_FORMAT 0x807C // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits @@ -292,11 +196,6 @@ //14 P8_29 57 0x8e4/0e4 87 gpio2[23] //15 P8_30 59 0x8ec/0ec 89 gpio2[25] -//generic GPIOs constants -//#define GPIO_CLEARDATAOUT 0x190 //SETDATAOUT is CLEARDATAOUT+4 -#define GPIO_OE 0x134 -#define GPIO_DATAIN 0x138 - .macro BELA_MINI_AND_JMP_TO .mparam DEST QBBS DEST, reg_flags, FLAG_BIT_BELA_MINI From 33bd71924892abe2b1bc5ffb643566852894a66d Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 2 Aug 2021 12:03:14 +0000 Subject: [PATCH 146/148] pru: ported changes applied to pru/pru_rtaudio.p in a5d3bc27..8b1e0e67 to pru/pru_rtaudio_irq.p Verified that without IS_AM572x the assembled code has not changed. Of course it does change when -DIS_AM572x --- pru/pru_rtaudio_irq.p | 152 +++++++++++++++++++++++++----------------- 1 file changed, 92 insertions(+), 60 deletions(-) diff --git a/pru/pru_rtaudio_irq.p b/pru/pru_rtaudio_irq.p index 52879dfcb..428c93771 100644 --- a/pru/pru_rtaudio_irq.p +++ b/pru/pru_rtaudio_irq.p @@ -2,6 +2,7 @@ .entrypoint START #include "../include/PruArmCommon.h" +#include "board_specific.h" // The jump from QBEQ WRITE_ONE_BUFFER, r1, 0 is too long when all the devices // are enabled. The code in there can probably be simplified and/or @@ -21,20 +22,11 @@ #define CTAG_IGNORE_UNUSED_INPUT_TDM_SLOTS -#define CLOCK_BASE 0x44E00000 -#define CLOCK_MCASP0 0x34 -#define CLOCK_SPI0 0x4C -#define CLOCK_SPI1 0x50 -#define CLOCK_L4LS 0x60 #define SCRATCHPAD_ID_BANK0 10 #define SCRATCHPAD_ID_BANK1 11 #define SCRATCHPAD_ID_BANK2 12 -#define SPI0_BASE 0x48030100 -#define SPI1_BASE 0x481A0100 -#define SPI_BASE SPI0_BASE - #define SPI_SYSCONFIG 0x10 #define SPI_SYSSTATUS 0x14 #define SPI_IRQSTATUS 0x18 @@ -68,8 +60,8 @@ #define SPI_INTR_BIT_RX3_FULL 14 #define SPI_INTR_BIT_EOW 17 // end of word -#define GPIO0 0x44E07000 -#define GPIO1 0x4804C000 +#define GPIO_OE 0x134 +#define GPIO_DATAIN 0x138 #define GPIO_CLEARDATAOUT 0x190 #define GPIO_SETDATAOUT 0x194 @@ -80,29 +72,20 @@ #define PRU_SYSTEM_EVENT_RTDM_WRITE_VALUE (1 << 5) | (PRU_SYSTEM_EVENT_RTDM - 16) #define C_ADC_DAC_MEM C24 // PRU0 mem -#define DAC_GPIO GPIO0 -#define DAC_CS_PIN (1<<5) // GPIO0:5 = P9 pin 17 #define DAC_TRM 0 // SPI transmit and receive #define DAC_WL 32 // Word length #define DAC_CLK_MODE 1 // SPI mode #define DAC_CLK_DIV 1 // Clock divider (48MHz / 2^n) -#define DAC_DPE 1 // d0 = receive, d1 = transmit #define AD5668_COMMAND_OFFSET 24 #define AD5668_ADDRESS_OFFSET 20 #define AD5668_DATA_OFFSET 4 #define AD5668_REF_OFFSET 0 -#define ADC_GPIO GPIO1 -#define ADC_CS_PIN (1<<16) // GPIO1:16 = P9 pin 15 -// for BELA_MINI, this is the same as DAC_CS_PIN, but the latter is disabled in DAC_WRITE -#define ADC_GPIO_BELA_MINI GPIO0 -#define ADC_CS_PIN_BELA_MINI (1<<5) // GPIO0:5 = P1 pin 6 #define ADC_TRM 0 // SPI transmit and receive #define ADC_WL 16 // Word length #define ADC_CLK_MODE 0 // SPI mode #define ADC_CLK_DIV 1 // Clock divider (48MHz / 2^n) -#define ADC_DPE 1 // d0 = receive, d1 = transmit #define AD7699_CFG_MASK 0xF120 // Mask for config update, unipolar, full BW #define AD7699_CHANNEL_OFFSET 9 // 7 bits offset of a 14-bit left-justified word @@ -183,13 +166,6 @@ #define CFG_REG_SPP 0x34 #define CFG_REG_PIN_MX 0x40 -// General constants for McASP peripherals (used for audio codec) -#define MCASP0_BASE 0x48038000 -#define MCASP1_BASE 0x4803C000 - -#define MCASP0_DATAPORT 0x46000000 -#define MCASP1_DATAPORT 0x46400000 - #define MCASP_PWRIDLESYSCONFIG 0x04 #define MCASP_PFUNC 0x10 #define MCASP_PDIR 0x14 @@ -231,18 +207,16 @@ #define MCASP_SRCTL3 0x18C #define MCASP_SRCTL4 0x190 #define MCASP_SRCTL5 0x194 -#define MCASP_XBUF0 0x200 -#define MCASP_XBUF1 0x204 -#define MCASP_XBUF2 0x208 -#define MCASP_XBUF3 0x20C -#define MCASP_XBUF4 0x210 -#define MCASP_XBUF5 0x214 -#define MCASP_RBUF0 0x280 -#define MCASP_RBUF1 0x284 -#define MCASP_RBUF2 0x288 -#define MCASP_RBUF3 0x28C -#define MCASP_RBUF4 0x290 -#define MCASP_RBUF5 0x294 +#define MCASP_SRCTL6 0x198 +#define MCASP_SRCTL7 0x19C +#define MCASP_SRCTL8 0x1A0 +#define MCASP_SRCTL9 0x1A4 +#define MCASP_SRCTL10 0x1A8 +#define MCASP_SRCTL11 0x1AC +#define MCASP_SRCTL12 0x1B0 +#define MCASP_SRCTL13 0x1B4 +#define MCASP_SRCTL14 0x1B8 +#define MCASP_SRCTL15 0x1BC #define MCASP_WFIFOCTL 0x1000 #define MCASP_WFIFOSTS 0x1004 #define MCASP_RFIFOCTL 0x1008 @@ -256,14 +230,6 @@ #define MCASP_XSTAT_XDATA_BIT 5 // Bit to test for transmit ready #define MCASP_RSTAT_RDATA_BIT 5 // Bit to test for receive ready -// Constants used for this particular audio setup -#define MCASP_BASE MCASP0_BASE -#define MCASP_DATAPORT MCASP0_DATAPORT -#define MCASP_SRCTL_X MCASP_SRCTL2 // Ser. 2 is transmitter -#define MCASP_SRCTL_R MCASP_SRCTL0 // Ser. 0 is receiver -#define MCASP_XBUF MCASP_XBUF2 -#define MCASP_RBUF MCASP_RBUF0 - #define MCASP_DATA_MASK 0xFFFF // 16 bit data #define MCASP_AHCLKRCTL_VALUE 0x8001 // Internal clock, not inv, /2; irrelevant? #define MCASP_AHCLKXCTL_VALUE 0x8001 // External clock from AHCLKX @@ -383,13 +349,6 @@ //14 P8_29 57 0x8e4/0e4 87 gpio2[23] //15 P8_30 59 0x8ec/0ec 89 gpio2[25] -//generic GPIOs constants -//#define GPIO1 0x4804c000 -#define GPIO2 0x481ac000 -//#define GPIO_CLEARDATAOUT 0x190 //SETDATAOUT is CLEARDATAOUT+4 -#define GPIO_OE 0x134 -#define GPIO_DATAIN 0x138 - .macro SEND_ERROR_TO_ARM .mparam error MOV r27, error @@ -599,6 +558,37 @@ DIGITAL: //[31:16]: data(1=high, 0=low), [15:0]: direction (0=output, 1=input) ) +#ifdef IS_AM572x +// same code as below with different mappings and without comments for brevity +// GPIO6-start + MOV r2, GPIO6 | GPIO_OE + LBBO r2, r2, 0, 4 + MOV r8, 0 + MOV r7, 0 + SET_GPIO_BITS r2, r8, r7, 5, 0, r27 + SET_GPIO_BITS r2, r8, r7, 6, 1, r27 + SET_GPIO_BITS r2, r8, r7, 18, 2, r27 + SET_GPIO_BITS r2, r8, r7, 4, 3, r27 + MOV r3, GPIO6 | GPIO_OE + SBBO r2, r3, 0, 4 +//GPIO6-end +//GPIO4-start + MOV r3, GPIO4 | GPIO_OE + LBBO r3, r3, 0, 4 + MOV r5, 0 + MOV r4, 0 + SET_GPIO_BITS r3, r5, r4, 3, 8, r27 + SET_GPIO_BITS r3, r5, r4, 29, 9, r27 + SET_GPIO_BITS r3, r5, r4, 26, 10, r27 + SET_GPIO_BITS r3, r5, r4, 9, 11, r27 + SET_GPIO_BITS r3, r5, r4, 23, 12, r27 + SET_GPIO_BITS r3, r5, r4, 19, 13, r27 + SET_GPIO_BITS r3, r5, r4, 22, 14, r27 + SET_GPIO_BITS r3, r5, r4, 20, 15, r27 + MOV r2, GPIO4 | GPIO_OE //use r2 as a temp registerp + SBBO r3, r2, 0, 4 //takes two cycles (10ns) +//GPIO4-end +#else // IS_AM572x //Preparing the gpio_oe, gpio_cleardataout and gpio_setdataout for each module //r2 will hold GPIO1_OE //load current status of GPIO_OE in r2 @@ -647,7 +637,7 @@ SET_GPIO_BITS_0_DONE: // r2 is now unused //GPIO2-start -//r3 will hold GPIO1_OE +//r3 will hold GPIO2_OE //load current status of GPIO_OE in r3 MOV r3, GPIO2 | GPIO_OE //it takes 200ns to go through the next instructions @@ -683,12 +673,37 @@ SET_GPIO_BITS_1_DONE: SBBO r3, r2, 0, 4 //takes two cycles (10ns) //GPIO2-end //r3 is now unused +#endif // IS_AM572x QBA START_INTERMEDIATE_DONE START_INTERMEDIATE: // intermediate step to jump to START QBA START START_INTERMEDIATE_DONE: +#ifdef IS_AM572x + MOV r2, GPIO6 | GPIO_DATAIN + MOV r3, GPIO4 | GPIO_DATAIN + LBBO r2, r2, 0, 4 + LBBO r3, r3, 0, 4 +//GPIO6 + READ_GPIO_BITS r2, 5, 0, r27 + READ_GPIO_BITS r2, 6, 1, r27 + READ_GPIO_BITS r2, 18, 2, r27 + READ_GPIO_BITS r2, 4, 3, r27 +//GPIO4 + READ_GPIO_BITS r3, 3, 8, r27 + READ_GPIO_BITS r3, 29, 9, r27 + READ_GPIO_BITS r3, 26, 10, r27 + READ_GPIO_BITS r3, 9, 11, r27 + READ_GPIO_BITS r3, 23, 12, r27 + READ_GPIO_BITS r3, 19, 13, r27 + READ_GPIO_BITS r3, 22, 14, r27 + READ_GPIO_BITS r3, 20, 15, r27 + MOV r2, GPIO6 | GPIO_CLEARDATAOUT + MOV r3, GPIO4 | GPIO_CLEARDATAOUT + SBBO r7, r2, 0, 8 + SBBO r4, r3, 0, 8 +#else // IS_AM572x //load current inputs in r2, r3 //r2 will contain GPIO1_DATAIN //r3 will contain GPIO2_DATAIN @@ -759,6 +774,7 @@ READ_GPIO_BITS_DONE: //reversing the order of the two lines above will swap the performances between the GPIO modules //i.e.: the first line will always take 145ns/185ns and the second one will always take 95ns/130ns, //regardless of whether the order is gpio1-gpio2 or gpio2-gpio1 +#endif // IS_AM572x JMP r28.w0 // go back to ADC_WRITE_AND_PROCESS_GPIO .macro HANG //useful for debugging @@ -846,10 +862,12 @@ DAC_CHANNEL_REORDER_DONE: // Bring CS line low to write to ADC .macro ADC_CS_ASSERT +#ifndef IS_AM572x IF_HAS_BELA_SPI_ADC_CS_JMP_TO BELA_CS MOV r27, ADC_CS_PIN_BELA_MINI MOV r28, ADC_GPIO_BELA_MINI + GPIO_CLEARDATAOUT QBA DONE +#endif // IS_AM572x BELA_CS: MOV r27, ADC_CS_PIN MOV r28, ADC_GPIO + GPIO_CLEARDATAOUT @@ -859,10 +877,12 @@ DONE: // Bring CS line high at end of ADC transaction .macro ADC_CS_UNASSERT +#ifndef IS_AM572x IF_HAS_BELA_SPI_ADC_CS_JMP_TO BELA_CS MOV r27, ADC_CS_PIN_BELA_MINI MOV r28, ADC_GPIO_BELA_MINI + GPIO_SETDATAOUT QBA DONE +#endif // IS_AM572x BELA_CS: MOV r27, ADC_CS_PIN MOV r28, ADC_GPIO + GPIO_SETDATAOUT @@ -1197,7 +1217,7 @@ SPI_NUM_CHANNELS_DONE: // Init SPI clock MOV r2, 0x02 - MOV r3, CLOCK_BASE + CLOCK_SPI0 + MOV r3, CLOCK_BASE + CLOCK_SPI SBBO r2, r3, 0, 4 // Reset SPI and wait for finish @@ -1219,11 +1239,11 @@ SPI_WAIT_RESET: SBBO r2, reg_spi_addr, SPI_MODULCTRL, 4 // Configure CH0 for DAC - MOV r2, (3 << 27) | (DAC_DPE << 16) | (DAC_TRM << 12) | ((DAC_WL - 1) << 7) | (DAC_CLK_DIV << 2) | DAC_CLK_MODE | (1 << 6) + MOV r2, (3 << 27) | (SPI_DPE_IS << 16) | (DAC_TRM << 12) | ((DAC_WL - 1) << 7) | (DAC_CLK_DIV << 2) | DAC_CLK_MODE | (1 << 6) SBBO r2, reg_spi_addr, SPI_CH0CONF, 4 // Configure CH1 for ADC - MOV r2, (3 << 27) | (ADC_DPE << 16) | (ADC_TRM << 12) | ((ADC_WL - 1) << 7) | (ADC_CLK_DIV << 2) | ADC_CLK_MODE + MOV r2, (3 << 27) | (SPI_DPE_IS << 16) | (ADC_TRM << 12) | ((ADC_WL - 1) << 7) | (ADC_CLK_DIV << 2) | ADC_CLK_MODE SBBO r2, reg_spi_addr, SPI_CH1CONF, 4 // Enable interrupts TX0_EMPTY__ENABLE for DACs and RX1_FULL__ENABLE for ADCs @@ -1293,8 +1313,8 @@ CHANNEL_COUNT_NOT_ZERO: SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4 // Start with frame count of 0 // enable MCASP interface clock in PRCM - MOV r2, 0x30002 - MOV r3, CLOCK_BASE + CLOCK_MCASP0 + MOV r2, CLOCK_MCASP_VALUE + MOV r3, CLOCK_BASE + CLOCK_MCASP SBBO r2, r3, 0, 4 // Prepare McASP0 for audio @@ -1319,6 +1339,18 @@ MCASP_ERROR_RECOVERY: // we also come back here if there are any issues while ru MCASP_REG_WRITE_EXT MCASP_SRCTL3, 0 MCASP_REG_WRITE_EXT MCASP_SRCTL4, 0 MCASP_REG_WRITE_EXT MCASP_SRCTL5, 0 +#ifdef IS_AM572x + MCASP_REG_WRITE_EXT MCASP_SRCTL6, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL7, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL8, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL9, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL10, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL11, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL12, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL13, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL14, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL15, 0 +#endif // IS_AM572x // 2. Configure all McASP registers except GBLCTL in the following order: // (a) Power Idle SYSCONFIG: PWRIDLESYSCONFIG. From b5841d5ac15b9d78004008da51ac4acd5a035e41 Mon Sep 17 00:00:00 2001 From: Giulio Moro Date: Mon, 2 Aug 2021 12:21:09 +0000 Subject: [PATCH 147/148] I2c_Codec: setting Mcasp serialisers in use depending on board (as usual, this is only honoured by pru_rtaudio_irq.p) --- core/I2c_Codec.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/I2c_Codec.cpp b/core/I2c_Codec.cpp index 5e9b87d45..375723c71 100644 --- a/core/I2c_Codec.cpp +++ b/core/I2c_Codec.cpp @@ -975,8 +975,13 @@ McaspConfig& I2c_Codec::getMcaspConfig() bool isI2s = (kTdmModeI2s == params.tdmMode); mcaspConfig.params.inChannels = getNumIns(); mcaspConfig.params.outChannels = getNumOuts();; +#ifdef IS_AM572x + mcaspConfig.params.inSerializers = {10}; + mcaspConfig.params.outSerializers = {11}; +#else // IS_AM572x mcaspConfig.params.inSerializers = {0}; mcaspConfig.params.outSerializers = {2}; +#endif // IS_AM572x mcaspConfig.params.numSlots = numSlots; mcaspConfig.params.slotSize = params.slotSize; mcaspConfig.params.dataSize = params.slotSize; From cb582b1073e4082d95d5ebd8c8a68cb4aac9d534 Mon Sep 17 00:00:00 2001 From: Dhruva_Gole Date: Sat, 14 Aug 2021 19:13:18 +0530 Subject: [PATCH 148/148] PruManager: added documentation --- Doxyfile | 2 +- core/PruManager.cpp | 7 ------- include/PruManager.h | 48 ++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/Doxyfile b/Doxyfile index 5913060b6..f8a37d968 100644 --- a/Doxyfile +++ b/Doxyfile @@ -2035,7 +2035,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = sinf_neon:=sinf_neon_hfp __MATH_FPABI:=1 __cplusplus +PREDEFINED = sinf_neon:=sinf_neon_hfp __MATH_FPABI:=1 __cplusplus = ENABLE_PRU_RPROC=1 = ENABLE_PRU_UIO=1 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/core/PruManager.cpp b/core/PruManager.cpp index 1db195ca6..c17f8c24a 100644 --- a/core/PruManager.cpp +++ b/core/PruManager.cpp @@ -11,12 +11,6 @@ PruManager::PruManager(unsigned int pruNum, int v) { - /* based on the value of pru_num to choose: - * 0 for PRUSS1 core 0 - * 1 for PRUSS1 core 1 - * 2 for PRUSS2 core 0 - * 3 for PRUSS2 core 1 - */ verbose = v; pruss = pruNum / 2 + 1; pruCore = pruNum % 2; @@ -53,7 +47,6 @@ PruManagerRprocMmap::PruManagerRprocMmap(unsigned int pruNum, int v) : void PruManagerRprocMmap::stop() { - // performs echo stop > state if(verbose) printf("Stopping %s\n", pruStringId.c_str()); IoUtils::writeTextFile(statePath, "stop"); diff --git a/include/PruManager.h b/include/PruManager.h index 589b828ac..a7d810af3 100644 --- a/include/PruManager.h +++ b/include/PruManager.h @@ -25,22 +25,53 @@ class PruManager int verbose; std::string pruStringId; public: + /** + * @param pruNum Select PRU and core number to run the pru code on
+ * @param v verbose flag + */ PruManager(unsigned int pruNum, int v); virtual ~PruManager() = 0; virtual int start(bool useMcaspIrq) = 0; + /** + * Load the firmware and start the PRU + * @param path path to a PRU firmware file that is suitable to be loaded by the child class's underlying driver. + */ virtual int start(const std::string& path) = 0; + /** + * Stops the PRU + */ virtual void stop() = 0; + /** + * Obtain a pointer to the PRU's own DATA RAM + */ virtual void* getOwnMemory() = 0; + /** + * Obtain a pointer to the PRUSS shared RAM + */ virtual void* getSharedMemory() = 0; }; #if ENABLE_PRU_RPROC == 1 +/** + * \brief Support for interaction with PRU via + * Remote Proc + Mmap + * \nosubgrouping + */ class PruManagerRprocMmap : public PruManager { -// use rproc for start/stop and mmap for memory sharing public: + /** + * @param pruNum select PRUSS and core On BBAI:
+ * 0 for PRUSS1 core 0
+ * 1 for PRUSS1 core 1
+ * 2 for PRUSS2 core 0
+ * 3 for PRUSS2 core 1 + */ PruManagerRprocMmap(unsigned int pruNum, int v); void stop(); + /** + * Loads a firmware ELF `.out` suitable for rproc. + */ int start(bool useMcaspIrq); int start(const std::string& path); void* getOwnMemory(); @@ -57,13 +88,22 @@ class PruManagerRprocMmap : public PruManager #endif // ENABLE_PRU_RPROC #if ENABLE_PRU_UIO == 1 +/** + * wrapper for libprussdrv for both start/stop and memory sharing + * It has the libprussdrv calls currently present in the codebase + */ class PruManagerUio : public PruManager { -/* wrapper for libprussdrv for both start/stop and memory sharing - * It has the libprussdrv calls currently present in the codebase -*/ public: + /** + * @param pruNum Select PRU on BBB:
+ * 0 for PRU 0
+ * 1 for PRU 1 + */ PruManagerUio(unsigned int pruNum, int v); + /** + * Loads a a binary of the firmware for Uio. + */ int start(bool useMcaspIrq); int start(const std::string& path); void stop();