• AVR Freaks

Framed SPI for Codec I2S?

Author
Howard Long
Super Member
  • Total Posts : 672
  • Reward points : 0
  • Joined: 2005/04/04 08:50:32
  • Status: offline
2009/02/03 03:53:54 (permalink)
0

Framed SPI for Codec I2S?

Folks
 
Before I go down a day or two of possibly fruitless discovery, in lieu of a DCI interface on the PIC32, I wonder if anyone has used the 16 bit (mono) or 32 bit (stereo) framed SPI function of the PIC32 (or for that matter the 16 bit framed SPI on the dsPIC/PIC24) to interface to a unidirectional I2S CODEC?
 
I am trying to interface a closed-IP low bit rate vocoder device that has an 8kHz sampling rate Codec interface (DVSI AMBE 2020) directly to a PIC32 without the need to use glue logic.
 
Cheers, Howard
#1

1 Reply Related Threads

    Howard Long
    Super Member
    • Total Posts : 672
    • Reward points : 0
    • Joined: 2005/04/04 08:50:32
    • Status: offline
    RE: Framed SPI for Codec I2S? 2009/02/08 16:47:54 (permalink)
    0
    In answer to my own question, for reference this code works with a 16 bit mono codec for full duplex operation using a single SPI port and mono codec with the PIC32 as master. This also demonstrates the use of half empty and half full operation of the DMA controllers to effectively simulate ping pong without resorting to chaining and thus limiting the use of scarce DMA resources.
     
    main.c

    #include <p32xxxx.h>
    #include <plib.h>
    #include "glb.h"
     
    #pragma config FPLLMUL = MUL_20, FPLLIDIV = DIV_2, FPLLODIV = DIV_1, FWDTEN = OFF
    #pragma config POSCMOD = HS, FNOSC = PRIPLL, FPBDIV = DIV_1
     
    #define SPICHN 2
    #define DMASPITXCHN 0
    #define DMASPIRXCHN 1
     
    BOOL _bTxDone0=FALSE;
    BOOL _bTxDone1=FALSE;
    BOOL _bRxDone0=FALSE;
    BOOL _bRxDone1=FALSE;

    // The transmit DMA IRQ
    void __ISR(_DMA0_VECTOR,ipl5) DmaHandler0(void)
    {
     int evFlags;    // event flags when getting the interrupt
     DmaChnClrIntFlag(DMASPITXCHN);  // acknowledge the INT controller, we're servicing int
     evFlags=DmaChnGetEvFlags(DMASPITXCHN); // get the event flags
     if(evFlags&DMA_EV_SRC_FULL)
     {
      _bTxDone1=TRUE;
      DmaChnClrEvFlags(DMASPITXCHN,DMA_EV_SRC_FULL);
     }
     if(evFlags&DMA_EV_SRC_HALF)
     {
      _bTxDone0=TRUE;
      DmaChnClrEvFlags(DMASPITXCHN,DMA_EV_SRC_HALF);
     }
    }
     
    // The receive DMA IRQ
    void __ISR(_DMA1_VECTOR,ipl5) DmaHandler1(void)
    {
     int evFlags;    // event flags when getting the interrupt
     DmaChnClrIntFlag(DMASPIRXCHN);  // acknowledge the INT controller, we're servicing int
     evFlags=DmaChnGetEvFlags(DMASPIRXCHN); // get the event flags
     if(evFlags&DMA_EV_DST_FULL)
     {
      _bRxDone1=TRUE;
      DmaChnClrEvFlags(DMASPIRXCHN,DMA_EV_DST_FULL);
     }
     if(evFlags&DMA_EV_DST_HALF)
     {
      _bRxDone0=TRUE;
      DmaChnClrEvFlags(DMASPIRXCHN,DMA_EV_DST_HALF);
     }
    }

    int main(void)
    {
     static U16 au16Tx[128];
     static U16 au16Rx[128];
     
     // For Explorer 16 allow use of LEDs for debugging
     mJTAGPortEnable(0);
     
     /* Set the system and peripheral bus speeds and enable the program cache*/
      SYSTEMConfigPerformance(80000000);
     
     /* Setup to use the external interrupt controller. */
      INTEnableSystemMultiVectoredInt();
     {
      int i;
      
      // Start with full buffer data
      for (i=0;i<128;i++)
      {
       au16Tx[i]=i;
       au16Rx[i]=0; // Clear receiver data so we can see data coming in
      } 
      
      // Setup SPI
      SpiChnRxTxIntDisable(SPICHN);
      SpiChnFaultIntDisable(SPICHN);
      SpiChnClose(SPICHN);
      SpiChnClrIntFlags(SPICHN);
      SpiChnOpen(SPICHN,SPICON_MSTEN|SPICON_SSEN|SPICON_MODE16|SPICON_ON|SPICON_SIDL|SPICON_FRMEN|SPICON_FRMPOL,625);
      
      // Prepare DMA Rx channel
      DmaChnOpen(DMASPIRXCHN,DMA_CHN_PRI2,DMA_OPEN_AUTO);
      DmaChnSetEventControl(DMASPIRXCHN,DMA_EV_START_IRQ_EN|DMA_EV_START_IRQ(_SPI2_RX_IRQ));
      DmaChnSetTxfer(DMASPIRXCHN,(void*)&SPI2BUF,au16Rx,sizeof(au16Rx[0]),sizeof(au16Rx),sizeof(au16Rx[0]));
      DmaChnSetEvEnableFlags(DMASPIRXCHN,DMA_EV_DST_FULL | DMA_EV_DST_HALF);
      DmaChnSetIntPriority(DMASPIRXCHN,INT_PRIORITY_LEVEL_5,INT_SUB_PRIORITY_LEVEL_3);
      DmaChnIntEnable(DMASPIRXCHN);
      _bRxDone0=FALSE;   // clear the interrupt flag we're  waiting on
      _bRxDone1=FALSE;   // clear the interrupt flag we're  waiting on
      DmaChnEnable(DMASPIRXCHN);
     
      // Prepare DMA Tx channel
      DmaChnOpen(DMASPITXCHN,DMA_CHN_PRI2,DMA_OPEN_AUTO);
      DmaChnSetEventControl(DMASPITXCHN,DMA_EV_START_IRQ_EN|DMA_EV_START_IRQ(_SPI2_TX_IRQ));
      DmaChnSetTxfer(DMASPITXCHN,au16Tx,(void*)&SPI2BUF,sizeof(au16Tx),sizeof(au16Tx[0]),sizeof(au16Tx[0]));
      DmaChnSetEvEnableFlags(DMASPITXCHN,DMA_EV_SRC_FULL | DMA_EV_SRC_HALF);
      DmaChnSetIntPriority(DMASPITXCHN,INT_PRIORITY_LEVEL_5,INT_SUB_PRIORITY_LEVEL_3);
      DmaChnIntEnable(DMASPITXCHN);
      _bTxDone0=FALSE;   // clear the interrupt flag we're  waiting on
      _bTxDone1=FALSE;   // clear the interrupt flag we're  waiting on
      DmaChnStartTxfer(DMASPITXCHN,DMA_WAIT_NOT,0); // force the DMA transfer: the SPI TBE flag it's already been active
     
      // Poll for buffer statuses
      while(TRUE)
      {

       if (_bRxDone0)
       {
        _bRxDone0=FALSE;
       }   

       if (_bRxDone1)
       {
        _bRxDone1=FALSE;
       }   

       if (_bTxDone0)
       {
        int j;
        
        _bTxDone0=FALSE;
     
        // Fill the bottom half of the buffer only
        for (j=0;j<64;j++)
        {
         au16Tx[j]=i;
         i++;
        } 
       }   

       if (_bTxDone1)
       {
        int j;
        
        _bTxDone1=FALSE;

        // Fill the top half of the buffer only
        for (j=64;j<128;j++)
        {
         au16Tx[j]=i;
         i++;
        } 
       }   
      } 
     }
     return 0;
    }


     
    glb.h

    #define TRUE 1
    #define FALSE 0
     
    typedef int BOOL;

    typedef char S8;
    typedef short S16;
    typedef long S32;
    typedef long long S64;
    typedef short Q15;
    typedef long Q1516;
    typedef unsigned char U8;

    typedef unsigned short U16;
    typedef unsigned long U32;
    typedef unsigned long long U64;
     
    #define Nop() asm("nop")


     
    Howard
    #2
    Jump to:
    © 2019 APG vNext Commercial Version 4.5