Hot!SPI SDO, LRCK (SS1) not working in audio mode...

Author
TonyShell
Starting Member
  • Total Posts : 62
  • Reward points : 0
  • Joined: 2016/05/22 20:51:01
  • Location: 0
  • Status: online
2017/09/09 10:27:58 (permalink)
0

SPI SDO, LRCK (SS1) not working in audio mode...

Hi all,
  I'm trying to get the AK4953 chip working on the MEBII board with a PIC32 Starter Kit (PIC32MZ2048EFH144).  I set up I2C to set the registers on the chip and that's working, I can get the beep generator to work.  I want to do stereo audio from a file, so I set up SPI in audio mode, but I can't get the SDO or SS1 (LRCK) outputs to work.  The clock (BICK) is working fine.  I set up the audio chip for slave mode, not using MCLK, only BICK.  I'm doing it through DMA and the "block transferred" interrupt is working and fires every ~0.5 seconds as it should.  The DMA is sending to the SPI1BUF.  Do I need to set up a receive DMA also?  If so, how do I do that simultaneously?  Thanks for any help!  Relevant code below:
 

 
 
 
// set up Peripheral Pin Select
SYSKEY = 0xAA996655; // Unlocking sequence.
SYSKEY = 0x556699AA;
CFGCONbits.IOLOCK = 0; // unlock Peripheral Pin Select
RPD14Rbits.RPD14R = 0b0000; // disconnect RPD14 from outputs - it's an input
SDI1Rbits.SDI1R = 0b1011; // set SDI1 to GPIO pin RD14 (pin 69)
RPB10Rbits.RPB10R = 0b0101; // set GPIO pin RB10 (pin 49) to SDO1
SS1Rbits.SS1R = 0b1001; // set SS1 to GPIO pin RF12 (pin 58) - input
RPF12Rbits.RPF12R = 0b0101; // set GPIO pin RF12 (pin 58) - output
CFGCONbits.IOLOCK = 1; // lock Peripheral Pin Select
SYSKEY = 0x33333333; // Locking sequence.
 
void InitAK4953A(void)
{
// CLOCK SETUP
// PLL Slave Mode (BICK pin)
Timer1 = 5;
while(Timer1);
AUDIO_PDN_PIN = 1; // power up
Timer1 = 10;
while(Timer1); // wait for power up
I2C_Write_Addr(0, 0); // dummy command
I2C_Write_Addr(5, 35); // PLL mode 2, Audio Interface mode 2
I2C_Write_Addr(6, 1); // Sampling Frequency mode 1
I2C_Write_Addr(0, 64); // power up Vcom (2.5VDC)
Timer1 = 4;
while(Timer1); // wait at least 3mS before powering up PLL
I2C_Write_Addr(1, 1); // turn on the PLL
Timer1 = 3;
while(Timer1); // PLL lock time is 2mS for this mode
 
// SPEAKER AMP OUTPUT SETUP
I2C_Write_Addr(2, 0x20); // send DAC output to speaker amplifier
I2C_Write_Addr(3, 0x40); // set speaker amplifier gain setting
I2C_Write_Addr(0xa, 0x70); // set ALC2 timers
I2C_Write_Addr(0xd, 0x28); // set ALC2 OREF and RGAIN1-0 bits
I2C_Write_Addr(0xb, 0xc1); // set up LMTH1-0, LMAT1-0, ZELMIN, ALC2 and LFST bits
I2C_Write_Addr(0x11, 0x91); // left volume at 0dB
I2C_Write_Addr(0x12, 0x91); // right volume at 0dB
I2C_Write_Addr(0x1d, 4); // set up Programmable Filter Path: PFDAC, ADCPF, PFSDO bits
I2C_Write_Addr(0, 0xd4); // power up DAC, Programmable Filter and Speaker: PMDAC = PMPFIL = PMSPK bits = ?0? ? ?1?
I2C_Write_Addr(2, 0xa3); // exit power save mode
}
// SCK1 - RD1 (109)
// SDI1 - RPD14 (PPS)
// SDO1 - RB10 (PPS)
// SS1 - RF12 (PPS)
void InitSPI(void)
{
    int rData;
    IEC3CLR = 0xe000; // disable all interrupts
    SPI1CON = 0; // stops and resets SPI1
    SPI1CON2 = 0; // reset audio settings
    rData = SPI1BUF;// clears the receive buffer
    IFS3CLR = 0xe000; // clear any existing event
    IPC27 = 0; // clear all SPI1 priorities
    SPI1BRG = 70;// buad rate = PBCLK2 (100MHz) / ((SPI1BRG + 1) * 2) or ~707.2KHz
    SPI1STATCLR = 0x40;// clear the Overflow
    SPI1CON2bits.AUDEN = 1; // enable audio codec support
    SPI1CON = 0x8020;// SPI ON, 8 bits transfer, Master mode
}
 
void InitDMA()
{
    audioaddr = _VirtToPhys((const void*)&audioBuffer); // transfer source physical address
    DMACONbits.ON = 1; // enable the DMA controller
    // DMA Channel 0...
    IEC4bits.DMA0IE = 0; // disable DMA Channel 0 interrupts
    IFS4bits.DMA0IF = 0; // clear any existing DMA Channel 0 interrupt flag
    DCH0CON = 0x3; // turn channel off, set to priority 3, no chaining
    DCH0ECON = 0; // no start or stop IRQ, no pattern match
    DCH0SSA = audioaddr; // transfer source physical address
    DCH0DSA = _VirtToPhys((const void*)&SPI1BUF); // transfer destination physical address
    DCH0SSIZ = 44100; // source size
    DCH0DSIZ = 2; // destination size
    DCH0CSIZ = 2; // 4 bytes transferred per event (32 bits)) *** have also tried 4 for CSIZ and DSIZ
    DCH0ECONbits.CHSIRQ = _TIMER_1_VECTOR;
    DCH0ECONbits.SIRQEN = 1;
    DCH0INTCLR = 0x00ff00ff; // clear existing events, disable all interrupts
    DCH0INTSET = 0x00090000; // enable Block Complete and error interrupts
    IPC33bits.DMA0IP = 7; // set DMA Channel 0 priority to 7
    IPC33bits.DMA0IS = 2; // set DMA Channel 0 sub-priority to 2
    IEC4bits.DMA0IE = 1; // enable DMA channel 0 interrupt
    DCH0CONbits.CHAEN = 1; // turn DMA Channel 0 on
    DCH0CONbits.CHEN = 1; // turn DMA Channel 0 on
}

post edited by TonyShell - 2017/09/09 10:36:34
#1

6 Replies Related Threads

    TonyShell
    Starting Member
    • Total Posts : 62
    • Reward points : 0
    • Joined: 2016/05/22 20:51:01
    • Location: 0
    • Status: online
    Re: SPI SDO, LRCK (SS1) not working in audio mode... 2017/09/10 19:28:41 (permalink)
    0
    Hi, no responses yet, I tried doing the transmit and receive DMA, still no LRCK or SDO pulses at all.  Code below, please help someone, I don't understand why this isn't working.  I've done everything that I see in the manuals.  I've also tried 2 as the cell/destination sizes also to no avail.  Is there something else I need to do?
     

    void InitDMA()
    {
    audiotxaddr = _VirtToPhys((const void*)&audioTxBuffer); // transmit buffer
    audiorxaddr = _VirtToPhys((const void*)&audioRxBuffer); // receive buffer
    spi1bufaddr = _VirtToPhys((const void*)&SPI1BUF); // SPI Channel 1 Read/Write Buffer address
    DMACONbits.ON = 1; // enable the DMA controller
    // DMA Channel 0...
    IEC4bits.DMA0IE = 0; // disable DMA Channel 0 interrupts
    IFS4bits.DMA0IF = 0; // clear any existing DMA Channel 0 interrupt flag
    DCH0CON = 0x3; // turn channel off, set to priority 3, no chaining
    DCH0ECON = 0; // no start or stop IRQ, no pattern match
    DCH0SSA = audiotxaddr; // transfer source physical address
    DCH0DSA = spi1bufaddr; // transfer destination physical address
    DCH0SSIZ = 44100; // source size
    DCH0DSIZ = 4; // destination size
    DCH0CSIZ = 4; // 4 bytes transferred per event (32 bits))
    DCH0ECONbits.CHSIRQ = _TIMER_1_VECTOR;
    DCH0ECONbits.SIRQEN = 1;
    DCH0INTCLR = 0x00ff00ff; // clear existing events, disable all interrupts
    DCH0INTSET = 0x00090000; // enable Block Complete and error interrupts
    IPC33bits.DMA0IP = 7; // set DMA Channel 0 priority to 7
    IPC33bits.DMA0IS = 2; // set DMA Channel 0 sub-priority to 2
    IEC4bits.DMA0IE = 1; // enable DMA channel 0 interrupt
    DCH0CONbits.CHAEN = 1; // turn DMA Channel 0 on
    DCH0CONbits.CHEN = 1; // turn DMA Channel 0 on
    // DMA Channel 1...
    IEC4bits.DMA1IE = 0; // disable DMA Channel 0 interrupts
    IFS4bits.DMA1IF = 0; // clear any existing DMA Channel 0 interrupt flag
    DCH1CON = 0x3; // turn channel off, set to priority 3, no chaining
    DCH1ECON = 0; // no start or stop IRQ, no pattern match
    DCH1SSA = spi1bufaddr; // transfer source physical address
    DCH1DSA = audiorxaddr; // transfer destination physical address
    DCH1SSIZ = 4; // source size
    DCH1DSIZ = 44100; // destination size
    DCH1CSIZ = 4; // 4 bytes transferred per event (32 bits))
    DCH1ECONbits.CHSIRQ = _TIMER_1_VECTOR;
    DCH1ECONbits.SIRQEN = 1;
    DCH1INTCLR = 0x00ff00ff; // clear existing events, disable all interrupts
    DCH1INTSET = 0x00090000; // enable Block Complete and error interrupts
    IPC33bits.DMA1IP = 7; // set DMA Channel 0 priority to 7
    IPC33bits.DMA1IS = 2; // set DMA Channel 0 sub-priority to 2
    IEC4bits.DMA1IE = 1; // enable DMA channel 0 interrupt
    DCH1CONbits.CHAEN = 1; // turn DMA Channel 0 on
    DCH1CONbits.CHEN = 1; // turn DMA Channel 0 on
    }
    void __ISR(_DMA0_VECTOR, IPL7SRS) __DMA0Interrupt(void)
    {
    // To minimize context saving, do not make any function calls from within the ISR.
    T1CONCLR = 0x8000; // Stop timer by clearing bit 15 (TON).
    LATHbits.LATH1 = ~LATHbits.LATH1;
    // reset DMA channel 0
    DCH0SSIZ = 44100; // source size
    DCH0SSA = audiotxaddr; // transfer source physical address
    DCH0DSIZ = 4; // destination size
    DCH0CSIZ = 4; // 4 bytes transferred per event (32 bits))
    DCH0INTCLR = 0xFF; // Clear the DMA Channel Interrupt Flags.
    IFS4bits.DMA0IF = 0; // Be sure to clear the DMA Channel 0 interrupt status.
    T1CONSET = 0x8000; // Start timer by setting bit 15 (TON).
    }
    void __ISR(_DMA1_VECTOR, IPL7SRS) __DMA1Interrupt(void)
    {
    // To minimize context saving, do not make any function calls from within the ISR.
    //T1CONCLR = 0x8000; // Stop timer by clearing bit 15 (TON).
    LATHbits.LATH2 = ~LATHbits.LATH2;
    // reset DMA channel 1
    DCH1SSA = spi1bufaddr; // transfer source physical address
    DCH1SSIZ = 4; // source size
    DCH1DSIZ = 44100; // destination size
    DCH1CSIZ = 4; // 4 bytes transferred per event (32 bits))
    DCH1INTCLR = 0xFF; // Clear the DMA Channel Interrupt Flags.
    IFS4bits.DMA1IF = 0; // Be sure to clear the DMA Channel 0 interrupt status.
    //T1CONSET = 0x8000; // Start timer by setting bit 15 (TON).
    }

    #2
    TonyShell
    Starting Member
    • Total Posts : 62
    • Reward points : 0
    • Joined: 2016/05/22 20:51:01
    • Location: 0
    • Status: online
    Re: SPI SDO, LRCK (SS1) not working in audio mode... 2017/09/11 20:31:11 (permalink)
    0
    OK, so the SDO is actually working, I got the SDI and SDO mixed at first.  But the LRCK (SS) isn't working and I don't understand it.  Can someone help here?  What do I need to do to get this working?
    #3
    friesen
    Super Member
    • Total Posts : 1645
    • Reward points : 0
    • Joined: 2008/05/08 05:23:35
    • Location: Indiana, USA
    • Status: offline
    Re: SPI SDO, LRCK (SS1) not working in audio mode... 2017/09/12 09:53:20 (permalink)
    3.5 (2)
    You don't have to set up a receive if you set the dissdi bit.
     
    You may alread know this, but using LATHbits inside an interrupt is a bad idea on the 32 series.  You really need to use the atomic LATH SET CLR INV instead, otherwise your LATH port will RMW when you don't want it to.
     
    Here is some code I have on a DA that works for me, its 24 bit mono mode.
     
    void InitDac(int BckFreq) {
        int a;
        SPI3CON = 0; //reset
        a = SPI3BUF;
        SPI3BRG = 0;//SYS_CLK_BUS_REFERENCE_1 / (2 * BckFreq) - 1;
        SPI3CONSET = _SPI3CON_MSTEN_MASK;
        SPI3CONSET = _SPI3CON_MODE32_MASK | _SPI3CON_MODE16_MASK;//24 bit audio
        SPI3CONSET = _SPI3CON_ENHBUF_MASK | _SPI3CON_STXISEL_MASK | _SPI3CON_MCLKSEL_MASK | _SPI3CON_ENHBUF_MASK | _SPI3CON_DISSDI_MASK;
        SPI3CON2SET = _SPI3CON2_AUDEN_MASK | _SPI3CON2_AUDMONO_MASK;
        SPI3CON2bits.AUDMOD = 1;//Left justified mode
        SPI3CONSET = _SPI3CON_ON_MASK;
        SPI3STATbits.SPIROV = 0; //clear overflow flag
        DMACONSET = _DMACON_ON_MASK;
        //TX setup
        DCH0CON = 0;
        DCH0ECON = 0;
        DCH0INT = 0;
        DCH0ECONbits.CHSIRQ = _SPI3_TX_VECTOR;
        DCH0ECONbits.SIRQEN = 1;
        DCH0INTbits.CHBCIE = 1;//Channel block transfer complete interrupt enable
        DCH0SSA = KVA_TO_PA(&silence); //Source
        DCH0SSIZ = DAC_Tx_Dma_Size * sizeof(long);
        DCH0DSA = KVA_TO_PA(&SPI3BUF); //Destination
        DCH0DSIZ = sizeof(long);
        DCH0CSIZ = sizeof(long);
        IEC4SET = _IEC4_DMA0IE_MASK;
        IPC33bits.DMA0IP = 3;
        DCH0CONSET = _DCH0CON_CHEN_MASK;
        IFS4CLR = _IFS4_SPI3TXIF_MASK;
        DAC_FMT_LFJ;
        DAC_XSMT_UNMUTE;
        SetDacFreq(BckFreq);//Sets REF trim bits for correct clock rate
    }

    void __ISR(_DMA0_VECTOR, IPL3AUTO) DmaHandler0(void) {
        int HP = HeadPtr & DAC_Ptr_Mask;
        int TP = TailPtr & DAC_Ptr_Mask;
        if (HP == TP) {
     DCH0SSA = KVA_TO_PA(&silence); //Source
     DAC_XSMT_MUTE;
        } else {
     DCH0SSA = KVA_TO_PA(&txBuffer[TailPtr]); //Source
     DAC_XSMT_UNMUTE;
     TailPtr += DAC_Tx_Dma_Size;
     if (TailPtr == DAC_TxBuffSize) {
         TailPtr = 0;
     }
        }
        IFS4CLR = _IFS4_DMA0IF_MASK;
        DCH0INTCLR = _DCH0INT_CHBCIF_MASK;
        DCH0CONSET = _DCH0CON_CHEN_MASK;
    }


    Erik Friesen
    #4
    TonyShell
    Starting Member
    • Total Posts : 62
    • Reward points : 0
    • Joined: 2016/05/22 20:51:01
    • Location: 0
    • Status: online
    Re: SPI SDO, LRCK (SS1) not working in audio mode... 2017/09/12 11:02:55 (permalink)
    0
    OK, thanks!  I'll try that later when I get off work.  I read about DISSDI, but it didn't explain it in any detail.  That'll certainly be a simpler solution than having two DMAs.
     
    As I said, the SCK (BICK) and SDO were working, but I wasn't getting LRCK.  I was thinking it had something to do with the way I set up up the PPS, but, hopefully, this solves it.
     
     
    #5
    TonyShell
    Starting Member
    • Total Posts : 62
    • Reward points : 0
    • Joined: 2016/05/22 20:51:01
    • Location: 0
    • Status: online
    Re: SPI SDO, LRCK (SS1) not working in audio mode... 2017/09/12 20:17:45 (permalink)
    3.5 (2)
    I found the problem!  While the DISSDI being on definitely made things easier, the real problem is that the MEB II has the audio codec SDO pin on SPI1, which is the same pin as the JTAG TDO output.  So, using this code to disable JTAG control of those outputs gives control of the SDO pin back to SPI1:
     

    // Disable JTAG control of outputs
    CFGCONbits.JTAGEN = 0;
    CFGCONbits.TDOEN = 0; // I think this is the only one you need, but I'm not taking chances...
    CFGCONbits.TROEN = 0;

     
    Anyway, problem solved!  Thanks for your help, friesen!
    #6
    TonyShell
    Starting Member
    • Total Posts : 62
    • Reward points : 0
    • Joined: 2016/05/22 20:51:01
    • Location: 0
    • Status: online
    Re: SPI SDO, LRCK (SS1) not working in audio mode... 2017/09/13 14:46:12 (permalink)
    0
    Hey, if anyone knows anything about the AK4953A audio codec chip on the MEB II board, I could use some help.  I got the audio working.  I'm using I2C to write to the registers and SPI with audio mode to send the info to the chip.  I'm operating in PLL mode 2 (PLL3-0 bits = 0010 - see table 5), Audio Interface Format mode 3 (I2S Compatible DIF1-0 = 3 - see table 19 & figure 24), slave mode (M/S bit = 0).  I want to clock the audio at 22.05kHz using 16 bits/channel, so these settings should give me that.  Table 5 says 32fs and figure 24 shows 32 bits, 16 for each channel.  So, my drive frequency should be 22,050Hz * 32bits/frame = 705,600Hz.  But I need double that to get the audio at the right frequency.  What am I doing wrong?  Code for writing registers below:
     

    // CLOCK SETUP
    // PLL Slave Mode (BICK pin)
    Timer1 = 5;
    while(Timer1);
    AUDIO_PDN_PIN = 1; // power up
    Timer1 = 10;
    while(Timer1); // wait for power up
    I2C_Write_Addr(0, 0); // dummy command to reset all registers
    I2C_Write_Addr(5, 35); // PLL mode 2, Audio Interface mode 3 (I2S compatible)
    I2C_Write_Addr(6, 1); // Sampling Frequency mode 1 (12kHz < fs <= 24kHz)
    I2C_Write_Addr(0, 64); // power up Vcom (2.5VDC)
    Timer1 = 4;
    while(Timer1); // wait at least 3mS before powering up PLL
    I2C_Write_Addr(1, 1); // turn on the PLL
    Timer1 = 3;
    while(Timer1); // PLL lock time is 2mS for this mode
    // SPEAKER AMP OUTPUT SETUP
    I2C_Write_Addr(2, 0x20); // send DAC output to speaker amplifier
    I2C_Write_Addr(3, 0x40); // set speaker amplifier gain setting
    I2C_Write_Addr(0xa, 0x70); // set ALC2 timers
    I2C_Write_Addr(0xd, 0x28); // set ALC2 OREF and RGAIN1-0 bits
    I2C_Write_Addr(0xb, 0x1); // set up LMTH1-0, LMAT1-0, ZELMIN, ALC2 and LFST bits
    I2C_Write_Addr(0x11, AUDIO_INITIAL_VOLUME); // left volume
    I2C_Write_Addr(0x12, AUDIO_INITIAL_VOLUME); // right volume
    I2C_Write_Addr(0x1d, 4); // set up Programmable Filter Path: PFDAC, ADCPF, PFSDO bits
    I2C_Write_Addr(0, 0xd4); // power up DAC, Programmable Filter and Speaker: PMDAC = PMPFIL = PMSPK bits = ?0? ? ?1?
    I2C_Write_Addr(2, 0xa3); // exit power save mode

    #7
    Jump to:
    © 2017 APG vNext Commercial Version 4.5