This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Reconfiguring Audio and McASP drivers for custom hardware

Other Parts Discussed in Thread: OMAP-L137

Hi there, this may seem like a foolish question, but I'm having a great deal of trouble figuring out where to specify things such as which McASP to use (McASP0 or McASP1) and where to specify the McASP register settings for the hardware configuration on our board.  Our application is built on top of the audio echo example that came with the OMAP-L137 EVM but now I'm trying to target our custom hardware and I'm quite lost.

All the documentation I've seen so far refers to higher level viewpoints, I'm trying to modify the lowest level to work on our board.  There is the struct mcasp_chanparam[Audio_NUM_CHANS] in audioSamplee_io.c that has all the McASP register values but the values I write there get overwritten later on (i.e. when I check the register values during emulation the values have been changed.)  As you can probably tell, this is  my first time working with DSP/BIOS so I'm on a steep curve and any help would be appreciated.

thanks,

Dave

  • Is your custom hardware still based on the OMAP-L137?

    What is different between your board's McASP-connected pins and hardware vs. the EVM's?

    When you say that the values get overwritten in the McASP registers, do you ever see them with your programmed values or is it possible that these never get written there in the first place?

    Generally, there is a step in your code where you will call a XYZ_create() or XYZ_open() function for using McASP channel. In one of these calls will be a parameter or a pointer to a struct of parameters, and one of those should be which McASP port you are using. Often this is called in main() but there are other valid places like audioChannelSetup(), etc., just making up that function name.

  • Hi there, thanks for the quick response.  My hardware has a C6745.  I made a custom .gel file based on my external memory setup and that part of things seems to be fine. 

    McASP differences from the EVM are many:

    - EVM uses McASP1, I use McASP0

    - EVM receives all I2S clocks from codec, I need the DSP to generate at least MCLK.  My initial attempt was to have the DSP generate only MCLK and the ADC on board generate BITCLK and LRCLK(FSYNC). 

    - What I see in the registers is that McASP0 stays in default state, while the registers in McASP1 get partially setup, but not with the values I put in the struct.

    I'm a little confused by what I've read in the documentation.  There's stuff about creating the driver in the .tcf script versus creating it dynamically in the application.  The app that I'm building on does create the driver in the .tcf script but I don't see anything related to which physical McASP it will use.  I'll look for this *_create() or *_open() as you say.

    thanks much,

    Dave

  • Further details:

    My audioSample_main.c has the following:

    // start code

    /*
     * Mcasp init function called when creating the driver.
     */
    void audioUserMcaspInit()
    {

        /* power on the Mcasp 0 instance in the PSC  */
        Psc_ModuleClkCtrl(Psc_DevId_0, PSC_MCASP0_LPSC, TRUE);

        /* power on the Mcasp 1 instance in the PSC  */
        Psc_ModuleClkCtrl(Psc_DevId_1, PSC_MCASP1_LPSC, TRUE);

        Mcasp_init();
        audioMcaspParams = Mcasp_PARAMS;
        audioMcaspParams.hwiNumber = 8;
    }

    /*
     * Audio init function called when creating the driver.
     */
    void audioUserAudioInit()
    {
        Audio_init();
        audioParams = Audio_PARAMS;
        audioParams.adDevType = Audio_DeviceType_McASP;
        audioParams.adDevName = "/mcasp0";
        audioParams.acNumCodecs = 1;
        audioParams.acDevName[0] = "/aic310";
    }

    //end code

     

    audioMcaspParams is a struct of type Mcasp_Params as per this typedef:

    //start code

    typedef struct Mcasp_Params {
        Bool enablecache;
        /**< Option to select whether to enable cache or not(default is TRUE)      */

        Uint32 hwiNumber;
        /**< Variable to specify the Hwi number to be used by the driver
         * (default id is 0)                                                      */

        Bool isDataBufferPayloadStructure;
        /**< This is useful during the operation of the Mcasp in DIT mode.This
         * parameter indicates if the data buffer has to be interpreted as a
         * payload structure,i.e whether the channel status and user data is also
         * included in the application buffer and hence has to be appropriately
         * interpreted.(Default is FALSE).                                        */
       
        Mcasp_HwSetup mcaspHwSetup;
        /**< Register information for initialising the Mcasp hardware.            */
    }Mcasp_Params;

    // end code

    Mcasp_HwSetup is a struct that has everything except the base register address i.e. which McASP these parameters will be applied to.  I get the feeling that there is something here right under my nose that I'm just not seeing.....

     

    Dave

     

  • In audioUserMcaspInit(), you are powering on McASP1 as well as the intended McASP0. Is this just a carry-over from the original example or do you use both ports? If you are only going to use McASP0, you may want to power McASP1 down. Of course, this could be something to try once since it could lead to problems if your code is actually trying to access McASP1 right now. If that is the case, leave it powered on until you get the rest of this debugged.

    It is counter-intuitive to me why Mcasp_init() is called and then the params pointer is set. This would mean that whatever Mcasp_init() does is done with no knowledge of the values you put into Mcasp_PARAMS and therefore into audioMcaspParams. The same concern is true in audioUserAudioInit(). Since I do not have the whole application (not a hint to send it to me or post it), I cannot say this is wrong, just that it does not make much sense from my view on the outside looking in.

    What are the function calls you use to get and put audio samples? It is not clear yet what driver is being used to access the McASP. You can do this with GIO_xxxxx API calls, maybe SIO_xxxxx APIs, or sample-by-sample calls to get and McASP each sample.

    Whatever method is being used is being initialized by Mcasp_init(), so you may just need to look inside that function, maybe deeper but there is no way to tell without looking.

    Could  there be documentation or comments with the example that could point you to how to change the configuration?

  • Hi,

    You will need to modify the following files for the sample example to work on your custom board.

    1. audioSample.tci
    a. Need to specify the instance Number of Mcasp, codec and the I2c((interface to the codec).
    e.g.    bios.UDEV.instance("mcasp0").deviceId = 0;
    2. audioSample_main.c
    a. change the "audioMcaspParams" according to the custom setting required.(usually default settings should suffice).please take care to provide the appropriate "hwiNumber" and hardware setup values.
    3. audioSample_io.c
    a. change the channel parameters for the McASP to generate the appropriate clocks. Default configuration in the example is provided to use the clocks provided by the codec.(please note that if the clocks are to be provided by the Mcasp, appropriate changes need to be done to the Mcasp and codec parameters while creating it.)
    4. audio_evmInit.c
    a. Change the Pinmux settings for Mcasp and I2c instance (for the instances being used in the custom board).

    You may also need to accommodate changes according to your custom board settings like modifying the codec address in the codec driver, input clock to the codec etc.

    Mcasp_init()

    This function initializes the driver specific data structures. It also initializes all the information related to an instance(e.g. base Address, Interrupt numbers,EDMA channel numbers etc).This will be called only once in the lifetime of the application and before the device is created.This function is called by the "audioUserMcaspInit" which in turn is specified in the "audioSample.tci" File.

    Thanks & Regards,
    Imtiaz SMA

  • Hi there, thank you all for the detailed and informative replies. 

    By the end of Friday I had figured out that the parameter "bios.UDEV.instance("mcasp0").deviceId" referred to the number of the physical McASP to be used in that driver.  I put a big old comment in the code to that effect so others after me will be able to clearly see this.

    I also noticed that if I changed the struct definining the clock parameters in audioSample_io.c, the changes don't get applied.  I discovered by experimentation that defining the clock parameters when creating the driver does seem to result in them being applied.  My hardware design calls for the McASP do provide MCLK (HCLK in McASP parlance) and I have an ADC setup on the board to generate all the other clocks.  Just to clarify, when I need the McASP to provide the clocks, is it true that I need to specify the clock settings when creating the driver only, or do I need to specify them in both places?  (Both places being 1. When creating the driver in audiosample_main.c and 2. in the struct in audiosample_io.c)

    The documentation for the 674x seems to contradict itself on what the source is for the McASP reference clocks.  I've seen a clocking block diagram showing the McASP's clocked by SYSCLK/2 (i.e. 150MHz for a core running at 300MHz).  I've also seen somewhere else saying that they are clocked by the PLL input frequency, i.e. a 24MHz crystal on my current hardware design.  The behaviour of the hardware supports the second assertion as the MCLK now being generated by my McASP0 is my crystal frequency divided by the divider value I program to AHCLKXCTL.

    Is the reference clock source a selectable parameter or am I stuck with the PLL input frequency?

    thanks again for the support,

    Dave

     

  • So now I have all the clocks correctly configured (although still wondering if I can select SYSCLK/2 as the reference source rather than the xtal frequency).

    Remaining problem is that the system crashes when it calls SIO_create() to open the audio stream.  Is the source for that module available anywhere because I can't look in there right now to see where it's going off the rails.

  • SYSCLK/2 is the System Clock for most of the peripherals, including the McASPs. This is what clocks the internal logic of the peripheral, but not the clock for the actual shifting of data.

    In the datasheet SPRS377 on page 66 (rev b), Figure 6-10 shows the clock/PLL topology which includes the input xtal clock going directly to AUXCLK. Then in the McASP Users Guide SPRUFM1 on pages 25/26, the figures show AUXCLK coming in to a divider which can then drive the transmit and receive clocks and further dividers, as selected by the McASP control registers.

    Source for DSP/BIOS is not readily available; I have never been able to get a request filled to get it and I have been supporting DSPs for many years.

    Since this same SIO_create() call does work on your OMAP-L137 EVM (right?), then the problem has to be in the parameters being passed to it or the power/clocking to the module. It does show a weakness in the SIO module if it is crashing, but that is another issue.

    Can you post the actual SIO_create() call line, and all of the arguments with what is in any structs?

  • Hello,

    Have you checked if the SIO_create() control comes in to the following functions (in the order mentioned)
    1. The audio driver "audioMdBindDev" function
    2. The codec driver "aic31MdCreateChan" function
    3. The I2c driver "i2cMdCreateChan" function.
    4. The Mcasp driver "mcaspMdCreateChan" function.

     you have also mentioned that you are using a custom board. I am not sure whether you have a AIC31 codec on your custom board.
    Also please post the error message along with the code snippets.

    Thanks & Regards,
    Imtiaz SMA

  • Regarding SYSCLK/2, what I observe is that the HCLK frequency I get out is my crystal frequency divided by the divider value in AHCLKXCTL.  Is that as it should be?

    On the more important subject of the getting the audio sample code to work on our hardware:

    Pertinent details of my hardware:

    - McASP0 is connected to a stereo ADC and a stereo DAC, both hardware configured to run in I2S format.  The ADC is the master for SCLK and LRCLK but it needs MCLK provided externally.  My intention is to use AHCLKX0 as an output driving MCLK and receive the other clocks for both transmit and receive from the ADC.

    - When I manually set the clock registers in audioSample_main.c as here:

     /* power on the Mcasp0 instance in the PSC  */
        Psc_ModuleClkCtrl(Psc_DevId_0, PSC_MCASP0_LPSC, TRUE);

        // Initialize McASP.  The physical McASP to be initialized is specified in the project .tci
        // file by the parameter .deviceId
        Mcasp_init();
        // It appears that all non-default McASP setup parameters should be entered here.  This could be
        // wrapped up into a struct for neatness
        audioMcaspParams = Mcasp_PARAMS;
        audioMcaspParams.hwiNumber = 8;

    // RX Parameters
        // 24-bits
        audioMcaspParams.mcaspHwSetup.rx.mask = 0x00FFFFFF;   
       
        // 1-bit delay/MSB-1st/PAD=0/padbit=0/32-bit slot/DMA/no rotation
        audioMcaspParams.mcaspHwSetup.rx.fmt = 0x000180F0;
       
        // 2-slot TDM/word-long fsync/external/falling edge frame start   
        audioMcaspParams.mcaspHwSetup.rx.frSyncCtl = 0x00000111;

        // Rising edge/external/divide-by-4 from hclk (mclk)
        audioMcaspParams.mcaspHwSetup.rx.clk.clkSetupClk = 0x00000083;

        // external/noninverted/divide-by-3 from auxclk2
        audioMcaspParams.mcaspHwSetup.rx.clk.clkSetupHiClk = 0x00000002;

        // time slots 0 and 1 are active
        audioMcaspParams.mcaspHwSetup.rx.tdm = 0x00000003;

    // TX Parameters
        // 24-bits
        audioMcaspParams.mcaspHwSetup.tx.mask = 0x00FFFFFF;

        // 1-bit delay/MSB-1st/PAD=0/padbit=0/32-bit slot/DMA/no rotation
        audioMcaspParams.mcaspHwSetup.tx.fmt = 0x000180F0;

        // 2-slot TDM/word-long fsync/external/falling edge frame start   
        audioMcaspParams.mcaspHwSetup.tx.frSyncCtl = 0x00000111;

        // Rising edge/external/divide-by-4 from hclk (mclk)
        audioMcaspParams.mcaspHwSetup.tx.clk.clkSetupClk = 0x00000083;

        // external/noninverted/divide-by-3 from auxclk2
        audioMcaspParams.mcaspHwSetup.tx.clk.clkSetupHiClk = 0x00008002;

        // time slots 0 and 1 are active
        audioMcaspParams.mcaspHwSetup.tx.tdm = 0x00000003;

    // Global Parameters
        // all pins McASP
        audioMcaspParams.mcaspHwSetup.glb.pfunc = 0x0;

        // outputs: AHCLKX and AXR1, all others are inputs
        audioMcaspParams.mcaspHwSetup.glb.pdir = 0x08000002;

        // All clock dividers, serializers and state machines enabled
        audioMcaspParams.mcaspHwSetup.glb.ctl = 0x0001F1F;
    }

    I can get the right clocks all going to the right places, but my SIO_create() call still hangs up, giving these messages in the execution graph details:

    394   SWI: end   KNL_swi (TSK scheduler) (0x1183dbac) state = done
    395   SEM: post __TSK_mutex (0x11834d8c) count = 0
    396   SEM: post __TSK_mutex (0x11834d8c) count = 0
    397   SEM: post __TSK_mutex (0x11834d8c) count = 0
    398   SEM: post __TSK_mutex (0x11834d8c) count = 0
    399   SEM: post __TSK_mutex (0x11834d8c) count = 0
    400   SEM: post __TSK_mutex (0x11834d8c) count = 0
    401   SEM: post __TSK_mutex (0x11834d8c) count = 0
    402   SEM: post __TSK_mutex (0x11834d8c) count = 0
    403   SEM: post __TSK_mutex (0x11834d8c) count = 0
    404   EXC_exceptionHandler: EFR=0x2
    405     NRP=0x0
    406     mode=supervisor
    407   Internal exception: IERR=0x1
    408     Instruction fetch exception
    409   SYS abort called with message 'Run-time exception detected, aborting ...'

    My SIO_create() call is as follows:

        SIO_Attrs sioAttrs;

        sioAttrs       = SIO_ATTRS;
        sioAttrs.nbufs = NUM_BUFS;    // 4   
        sioAttrs.align = BUFALIGN;    // 128   
        sioAttrs.model = SIO_ISSUERECLAIM;

        mcasp_chanparam[0].edmaHandle = hEdma;
        mcasp_chanparam[1].edmaHandle = hEdma;

        /* open the I/O streams */
        outStream = SIO_create("/dioAudioOUT", SIO_OUTPUT, BUFSIZE, &sioAttrs); // ,,128,

     

    The code does work on the EVM, so I agree it's something about our hardware config and how we're talking to it.  Our ADC and DAC are hardware configured so there is no need for any I2C configuration.  I've tried both leaving the AIC driver in the driver table and taking it out, I get the same results either way.

    thanks,

    Dave

  • David Anderson said:

    Regarding SYSCLK/2, what I observe is that the HCLK frequency I get out is my crystal frequency divided by the divider value in AHCLKXCTL.  Is that as it should be?

    Probably yes, but HCLK is a part of several signal names and not a specific one. I think you have the correct operation, with that caveat.

    David Anderson said:

    404   EXC_exceptionHandler: EFR=0x2
    405     NRP=0x0
    406     mode=supervisor
    407   Internal exception: IERR=0x1
    408     Instruction fetch exception
    409   SYS abort called with message 'Run-time exception detected, aborting ...'

    You can find the register descriptions for EFR and NRP and IERR in the CPU & Instruction Set Ref Guide for your processors. EFR=2 tells you this is an internal exception, NRP=0 means address 0 is where it happened (which is real bad but a good clue) and IERR=1 means a fetch error. The only part of that that is very meaningful is NRP=0, because you should never be executing anything at address 0 to which you could return (NRP = Non-maskable interrupt Return Pointer, aka exception return pointer). Since a NULL address pointer can easily result in a branch to 0, our "modern" C6000 cores (C674x, C64x+, at least) do not allow any memory to reside at address 0. This way any program or data accesses can result in an exception.

    But why do you get there?

    • A typo in a label that causes a lookup table to find a NULL function pointer
    • A handler function pointer in your init struct that was left NULL or 0
    • Stack overflow
    • Heap overflow

    I am sure there are several other reasons, but these are the first that come to mind. Stack and heap would be easiest to fix by increasing them (stack is more likely than heap). Hunting through the sioAttrs members should not be too bad, but typos that get past the compiler can be hard to find ("/dioAudioOUT" - check case?).

    It seems a little odd that both chanparam[0] and [1] are set to the same hEdma value. That may be something to look closely at, but not being directly familiar with this code means I am just guessing.

    Single stepping into the SIO_create function would mean debugging C6000 assembly code. This is generally to be avoid to keep your sanity. But if you need to do it, do an Assembly Step-Into command in CCS, which will put you into the Disassembly window. Then you can just do a bunch of Assembly Step-into commands, or scan down the list to find Branch/Call instructions, and you can do Run To Cursor to each one, then single-step over it. You can open the Registers window and look at the destination address if it is in a register, which is the most likely cause if the problem is really a branch-to-null.

    But I would definitely recommend trying to find the problem from the C-level first. Assembly debug is usually a case of desperation.

  • Because the code base I'm working on is an audio through example that works on the Spectrum Digital eval board, and the primary related difference between that board and my hardware is in the McASP connectivity, I'm leaning towards thinking that the problem lies somewhere there. 

    The primary differences between the two designs are:

    - My board uses McASP0, the spectrum digital board uses McASP1

    - My board requires the DSP to supply MCLK on ACHCLKX0 with the ADC providing BCLK and LRCLK to both the transmitter and the receiver.  The Spectrum digital board on the other hand receives all of the McASP clocks from the AIC31 codec.

    - The ADC and DAC on my board are hardware configured and therefor do not require any I2C configuration.  The I2C is not hooked up to anything on my board.  The Spectrum digital board uses I2C to configure the codec.

    As a test of my hardware, I found another example audio test application in the Spectrum Digital stuff that does not use DSP/BIOS at all.  After playing a little bit with the McASP setup parameters I now have my board happily passing audio (the DSP is just copying the input to the output on a per-sample basis).

    Sadly, copying those same adjusted McASP parameters back into the DSP/BIOS-based application doesn't get me anywhere, I still crash in the same place with the same error.

    Stepping through the assembly I get as far as function called DEV_match (assembly label) at which point everything goes off the rail.  I'm worried that single stepping through this stuff is not an accurate way to debug it as the constantly running McASP's and DMA's are involved meaning transient conditions that could be causing the problem are not readily observable.

    Dave

     

  • David Anderson said:

    Stepping through the assembly I get as far as function called DEV_match (assembly label) at which point everything goes off the rail.  I'm worried that single stepping through this stuff is not an accurate way to debug it as the constantly running McASP's and DMA's are involved meaning transient conditions that could be causing the problem are not readily observable.

    Please elaborate on "everything goes off the rail". Assembly single-stepping is very accurate but very tedious. If you were getting transients, that would point to a board-level power supply or decoupling deficiency. But that fact that you do go "off the rail" means you appear to be getting the problem. Perhaps it would be helpful to post screen shots of the disassembly window and registers window immediately before and immediately after the single-step that sends you away. If you can set a breakpoint at DEV_match it might make the process a little faster for you. Is is possible you are servicing an invalid interrupt at this fail point?

  • Hello,

    The audio example you are using currently assumes that the audio codec is connected to McASP (As in the spectrum digital evm) and hence tries to configure the same(through I2C).
    You will need to make changes to the configuration of the audio driver to remove the codec driver from being created.

    1. You will have to remove the reference to the codec and the driver from the audioSample.tci file.
    2. You will have to make changes to "audioUserAudioInit()"  function to reflect that the number of codecs used are 0
    "audioParams.acNumCodecs = 0;"
    3. Also since you are using multi slot TDM mode you will have to make the changes to "mcasp_chanparam " to reflect your settings
    (e.g. specify the buffer format as "Mcasp_BufferFormat_1SER_MULTISLOT_INTERLEAVED" or "Mcasp_BufferFormat_1SER_MULTISLOT_NON_INTERLEAVED", number of channels etc).

    Or alternatively I feel you can take a look at the mcaspDitExample provided in the PSP (driver) package for how to use the Mcasp driver directly using SIO. We feel that would suit you best. But please note that it demonstrates the uses of Mcasp standalone for playing a sample sine tone in DIT mode and you have to make necessary modifications to change it to TDM mode. Also please note that only the transmit channel is created here. You can perhaps try to use this example with appropriate changes.

    Also please refer the following documents for changing the configurations
    1) SPRU007H ( for BIOS application configuration (tcf configuration))
    2) SPRU423F (for understanding how SIO works)
    3) PSP user guide - section 9 - McASP driver(to understand changing the default configurations).

    Thanks & Regards,
    Imtiaz SMA

  • Hi, Anderson,

    How about this issue now? I also have come across this problem. Would you please share with me the method on fixing it?

    Thanks,

    Robin

  • I second the use of the mcaspDit Example code - I've got a (sort of) working audio I/O application for use with a separate custom codec board based on that (using McASP/EDMA drivers and SIO streams) with the audio passing code from the full fledged audio driver example thrown into that framework.

    Now if I could only get McASP1 working - McASP0 works fine, but McASP1 fails after a few seconds of noisy audio with the exact same register settings/code/external clock connection...

  • Noisy audio usually indicates that the peripheral and data are not in sync with the EDMA operations.

    How many serializers do you use with McASP0 and how many with McASP1?

  • 6 (3 in 3 out) with McASP0 and 8 (4 in 4 out) with McASP1.  - see this thread:

    http://e2e.ti.com/support/dsp/tms320c6000_floating-point_dsps/f/115/p/43109/150522.aspx#150522

    thanks!

  • Are you asking something different here, or is this the same issue as at the other thread which you originated?

  • same issue - sorry i realize now that was double posting! - just mentioning it conversationally.

    cheers,
    arvid