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.

AM3358: McASP read in burst mode

Part Number: AM3358

Hello!

I am using an Octavo Systems OSD3358 part which contains an AM3358 processor inside.  This processor is connected to a FPGA which is streaming 24-bit analogue samples from four ADCs at a variable rate.  I have chosen to use the McASP peripheral in burst mode using the frame sync (AFSR) signal to indicate the start of a transfer.  This is not an audio project but I am treating the streaming data from my ADCs as if they were audio samples.  The FPGA is the ACLKR master and there is no AHCLKR signal; the four ADC channels are connected to AXR0 thru AXR3.

After reading the McASP section in SPRUH73P many times and using the Linux and TI-RTOS code bases as a guide I have managed to get data to be transferred and read by the processor using by own code.  The code is running on Linux but I am not using any of the McASP drivers or ALSA code, moreover I am using /dev/mem to access the register space directly in my software.

For testing I am only using one AXR channel, the others have been set to inactive.  My software polls the RDATA flag in the RSTAT register in a loop and when it is set I make a read from the McASP data memory area (0x46000000 according to the memory map in SPRUH73P).  However it seems that I have to make two reads from this address in order for the RDATA flag to be cleared.  The first word does contain the ADC sample as expected but the second read always comes back as zero.  As the example driver code in Linux and the SDK use DMA transfers I don't have a reference to compare to so I'm uneasy that I've just coded a fix to an issue I don't understand.

From SPRUH73P, section 22.3.10.1.2 Transfers Through the Data Port (DAT) page 4683:

Similarly, for receive operations through the data port, the DMA/CPU should read from the same RBUF
data port address to service all of the active receive serializers. In addition, reads from the active receive
serializers through the data port return data in incremental (although not necessarily consecutive) order.
For example, if serializers 1, 2, and 3, are set up as active receivers, the DMA/CPU should read from the
RBUF data port address four times to obtain data for serializers 1, 2, and 3, in this exact order, upon each
receive data ready event.


This text suggests to make four reads for three serialisers but doesn't explain why.

One extra point is that I cannot seem to make use of the RBUF_0 register even if the McASP is configured to use the CFG port and not the DAT port; it always returns 0.

In summary, please can you answer why I have to make two reads instead of one and why I cannot use the RBUF_0 register in my code.

Thank you,

Simon

  • Hi Simon,

    I am internally checking with the team and I will get back to you within 24-48 hours.

    Regards,
    Krunal

  • Hi Simon,

    One thing which might cause the need to read twice on DAT port is that if McASP is configured to 24bits word size than a minimum of 24bits needs to be read from the port. Also, a single 32bit read is fine as the port will pad the unused bits. With regards to the CFG port, I am wondering if you could please confirm if the the register/bit RFMT/RBUSEL is set to 1.

    Regards,
    Krunal

  • Hi Krunal,

    Thanks for the quick response given the current world situation.

    The word size is set to 32-bit (i.e. RSSZ = Fh).  The FPGA keeps the receive clock going all the time and the frame sync pulses high for one clock cycle and then low.  So I am assuming that the McASP then clocks in 32 bits from 32 edges of the clock and then sets the interrupt flag to indicate that the data is received.  As far as I know I am making 32 bit reads with each transaction with the peripheral memory area.  If it helps, my setup code is here:

        mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, 0);
    
        /* clear GBLCTL register */
        mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTL_REG, 0);
    
        /* receiver setup */
        mcasp_set_reg(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, 2);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, 0x00ffffff);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, 0x000080f2 | RXPAD(2) | RXPBIT(23));
        mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, 0);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, 0);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, 0);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, 1);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_EVTCTLR_REG, XRDATA);     // interrupt reg
    
        /* transmit setup */
        mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, 0);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, 0x000000f2);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, 0);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, 0x40);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, 0x0);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, 0);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_EVTCTLX_REG, 0);
    
        mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(0), 2);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(1), 0);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(2), 0);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(3), 0);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_LBCTL_REG, 0);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_TXDITCTL_REG, 0);

    I've actually progressed to using userspace I/O and am being quite successful with this.  As you can tell from the code above I have enabled interrupts which I can service by using the blocking read() on the UIO driver.  This may not be the most efficient way of doing things but it helps my progress.  Interestingly now that I am using interrupts I only have to make one read from the memory area before the RDATA flag is cleared, as I would expect.  Maybe there's something to do with interrupts and this phenomenon?

    Lastly you can see that the ADC data is 24-bit, sent signed MSB and therefore I use the formatting block to sign-extend and rotate which is working really well.

    Although my code above doesn't set the RBUSEL bit to 1, I have tried that but without success - but that was before moving to UIO.  If time permits I can try that again.

    So you could say my issue is resolved but I'm still not happy that two reads need to be made.  We can leave the CFG/DAT port issue as I have a working solution.

    Thanks,

    Simon

  • Hi Simon,

    Thank you for sharing the above updates. With regards to the two reads, I am checking with our designers and I will get back to you. 

    Regards,
    Krunal

  • Hi Simon,

    We believe the TRM has a typo and I am waiting for the designers to confirm it. In the meantime, could you please check the following:

    1. In the non-workign setup, do you see any errors flags being set in the register RINTCTL?

    2. Also, please confirm that other serializers are indeed disabled. The best thing to do is run the setup and then dump the registers after the first received word is read. This way you’ll capture the real configuration during operation.

    3. As an experiment, please enable all four serializers and see if it requires n+1 read.

    Regards,
    Krunal

  • Hi Krunal,

    Thank you for the reply.  I've spent this morning back on the older code to see if I can get you some answers.  It seems though that I cannot reproduce the issue any more, which is very strange as it was quite reproducible before!  Here's the register dump for a working solution with four serialisers enabled with data being sent by the FPGA at 10kHz.  The register dump is performed after the first sample is read.

    setup_mcasp: setting up 4 serialisers
    mcasp_start_rx
    Collecting 3000 samples...
    PID_REG:       0x44307B02
    PWREMUMGT_REG: 0x00000002
    PFUNC_REG:     0x00000000
    PDIR_REG:      0x00000000
    PDOUT_REG:     0x00000000
    PDSET_REG:     0x20000000
    PDCLR_REG:     0x00000000
    TLGC_REG:      0x0000C291
    TLMR_REG:      0x00000000
    GBLCTL_REG:    0x0000001E
    AMUTE_REG:     0x00000000
    LBCTL_REG:     0x00000000
    TXDITCTL_REG:  0x00000000
    GBLCTLR_REG:   0x0000001F
    RXMASK_REG:    0x00FFFFFF
    RXFMT_REG:     0x0000D7F2
    RXFMCTL_REG:   0x00000000
    ACLKRCTL_REG:  0x00180000
    AHCLKRCTL_REG: 0x00000000
    RXTDM_REG:     0x00000001
    EVTCTLR_REG:   0x00000020
    RXSTAT_REG:    0x00000127
    RXTDMSLOT_REG: 0x00000000
    RXCLKCHK_REG:  0x00000000
    REVTCTL_REG:   0x00000000
    GBLCTLX_REG:   0x0000001F
    TXMASK_REG:    0x00000000
    TXFMT_REG:     0x000000F2
    TXFMCTL_REG:   0x00000000
    ACLKXCTL_REG:  0x00180040
    AHCLKXCTL_REG: 0x00180000
    TXTDM_REG:     0x00000000
    EVTCTLX_REG:   0x00000000
    TXSTAT_REG:    0x0000010C
    TXTDMSLOT_REG: 0x0000017F
    TXCLKCHK_REG:  0x00000000
    XEVTCTL_REG:   0x00000000
    SRCTL_0:       0x00000022
    SRCTL_1:       0x00000022
    SRCTL_2:       0x00000022
    SRCTL_3:       0x00000022
    SRCTL_4:       0x00000000
    SRCTL_5:       0x00000000

    For each sample that is taken I save the state of the RXSTAT register which is the register I think you wanted me to look at.  RINTCTL is the interrupt control register where you can enable interrupts so I haven't logged that as it is a constant value (0x00000020).  Now and again this register has the ROVRN bit set and I'm attributing that to the OS spending time elsewhere rather than on my process and therefore I miss a sample; it is usually set for one sample only.

    So by some magic or perhaps I've changed something that I cannot remember, the problem seems to have gone away.  I haven't tried using the CFG access on the data registers yet as I have to spend time on other parts of the project.

    Thank you for your time on this issue.  I'm happy to call this 'solved' if you are.

    Regards,

    Simon

  • Hi Simon,

    Thank you for the update and I will close the ticket for now. If you experience any issues in the future, please feel free to continue the discussions on our forums.

    Regards,
    Krunal