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.

Linux/AM3352: McASP read error

Part Number: AM3352


Tool/software: Linux

Hi.

I am trying to read MCASP using ALSA library. 

I found read error message. "arecord: pcm_read:2032: read error: Input/output error"

please check my system.

 

- I2S format

AM3352 receive I2S data and clock from Bluetooth module.

I2S bit format is 32bit slot size, 24bit word and Left justified.

- Kernel device driver (4.4.32 version)

I am not sure the tdm_slot function is correct -> (snd_soc_dai_set_tdm_slot(cpu_dai, 0xFFFFFF, 0xFFFFFF, 24, 32);

davinci-evm.c

static int pcm5102a_capture_hw_params(struct snd_pcm_substream *substream,
                 struct snd_pcm_hw_params *params)
{
  struct snd_soc_pcm_runtime *rtd = substream->private_data;
  struct snd_soc_dai *codec_dai = rtd->codec_dai;
  struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  struct snd_soc_card *soc_card = rtd->card;
    unsigned int bclk_freq = evm_get_bclk(params);
  int ret = 0;
  unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *)
         snd_soc_card_get_drvdata(soc_card))->sysclk;

  printk("[kdj6724] %s(%d) codec_dai:%s cup_dai:%s", __FUNCTION__, __LINE__, codec_dai->name, cpu_dai->name);
  /* set the codec system clock */
    ret = snd_soc_dai_set_clkdiv(cpu_dai, 1, sysclk/bclk_freq);
  if (ret < 0)
    return ret;

  /* set the CPU system clock */
    ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
  if (ret < 0)
    return ret;

  ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xFFFFFF, 0xFFFFFF, 24, 32);
  if (ret < 0)
    return ret;

  return 0;
}

// kdj6724
static struct snd_soc_ops pcm5102a_capture_ops = {
    .startup = evm_startup,
    .shutdown = evm_shutdown,
    .hw_params = pcm5102a_capture_hw_params,
    //.hw_params = pcm5102a_playback_hw_params,
};

static struct snd_soc_dai_link evm_dai_pcm5102a_in = { 
    .name       = "PCM5102A", //This is chosen arbitrarily.  Can be anything.
    .stream_name    = "Capture", //This comes from the PCM5102a driver create previously.
    .codec_dai_name = "pcm5102a-hifi", //This comes from the PCM5102a driver create previously
    .ops            = &pcm5102a_capture_ops, //This is a structure that we will create later.
    //.ops            = &pcm5102a_playback_ops, //This is a structure that we will create later.
    .dai_fmt    = (SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_LEFT_J |
               SND_SOC_DAIFMT_IB_NF),
};

davinci-mcasp.c

static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
int sample_width)
{
u32 fmt; 
u32 tx_rotate = (sample_width / 4) & 0x7; 
u32 mask = (1ULL << sample_width) - 1; 
u32 slot_width = sample_width;

/*
* For captured data we should not rotate, inversion and masking is
* enoguh to get the data to the right position:
* Format data from bus after reverse (XRBUF)
* S16_LE: |LSB|MSB|xxx|xxx| |xxx|xxx|MSB|LSB|
* S24_3LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB|
* S24_LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB|
* S32_LE: |LSB|DAT|DAT|MSB| |MSB|DAT|DAT|LSB|
*/
u32 rx_rotate = 0;

/*
* Setting the tdm slot width either with set_clkdiv() or
* set_tdm_slot() allows us to for example send 32 bits per
* channel to the codec, while only 16 of them carry audio
* payload.
*/
if (mcasp->slot_width) {
/* 
* When we have more bclk then it is needed for the
* data, we need to use the rotation to move the
* received samples to have correct alignment.
*/
slot_width = mcasp->slot_width;
rx_rotate = (slot_width - sample_width) / 4; 
}

/* mapping of the XSSZ bit-field as described in the datasheet */
fmt = (slot_width >> 1) - 1;

if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
printk("[kdj6724] %s(%d)", __FUNCTION__, __LINE__);
mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt),
RXSSZ(0x0F));
mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(fmt),
TXSSZ(0x0F));
mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate),
TXROT(7));
mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXROT(rx_rotate),
RXROT(7));
mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask);
}
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, mask);

mcasp_reg_dump(mcasp);
return 0;
}


- Error log

root@am335x-evm:~# arecord -f S24_LE -r44100 -c2 -D hw:0 -F0 --period-size=1024 -B0 --buffer-size=4096 test.wav             
[ 1593.396642] [kdj6724] soc_pcm_open(459)
[ 1593.400984] [kdj6724] soc_pcm_open(472)
[ 1593.404870] [kdj6724] davinci_mcasp_startup(1329)
[ 1593.415125] [kdj6724] soc_pcm_open(474)
[ 1593.425865] [kdj6724] soc_pcm_open(483)
[ 1593.433381] [kdj6724] soc_pcm_open(485)
[ 1593.443950] [kdj6724] soc_pcm_open(515)
[ 1593.453006] [kdj6724] evm_startup(40)
[ 1593.456750] [kdj6724] soc_pcm_open(517)
[ 1593.468324] [kdj6724] soc_pcm_open(529)
[ 1593.472254] [kdj6724] snd_soc_dai_stream_valid(46)
[ 1593.489922] [kdj6724] soc_pcm_open(532)
[ 1593.494655] [kdj6724] snd_pcm_mmap(3510)Recording WAVE 'test.wav' : Signed 24 bit Little Endian, Rate 44100 Hz, [kdj6724] snd_pcm_lib_ioctl_fifo_size(1819)
Stereo
[ 1593.533111] [kdj6724] snd_pcm_lib_ioctl_fifo_size(1819)
[ 1593.545722] [kdj6724] snd_pcm_lib_ioctl_fifo_size(1819)
[ 1593.558987] [kdj6724] snd_pcm_lib_ioctl_fifo_size(1819)
[ 1593.564374] [kdj6724] snd_pcm_lib_ioctl_fifo_size(1819)
[ 1593.584878] [kdj6724] snd_pcm_lib_ioctl_fifo_size(1819)
[ 1593.595159] [kdj6724] snd_pcm_lib_ioctl_fifo_size(1819)
[ 1593.607747] [kdj6724] snd_pcm_lib_ioctl_fifo_size(1819)
[ 1593.613125] [kdj6724] pcm5102a_capture_hw_params(105) codec_dai:pcm5102a-hifi cup_dai:48038000.mcasp[kdj6724] snd_soc_dai_stream_valid(46)
[ 1593.643995] [kdj6724] davinci_mcasp_hw_params(1131) cpu_dai->name:48038000.mcasp 
[ 1593.664293] [kdj6724] davinci_mcasp_set_dai_fmt(436) val:3 
[ 1593.678043] [kdj6724] davinci_mcasp_hw_params(1156) mcasp->op_mode:0 
[ 1593.684574] [kdj6724] mcasp_i2s_hw_param(933) stream:1 channels:2 total_slots:2
[ 1593.707050] [kdj6724] mcasp_i2s_hw_param(964) active_slots:2 active_serializers:1
[ 1593.714878] [kdj6724] mcasp_i2s_hw_param(980) 0x00000003
[ 1593.735435] [kdj6724] davinci_config_channel_size(792)
[ 1593.927522] [kdj6724] snd_pcm_capture_ioctl1(2919) cmd:-2146680495
[ 1593.933892] [kdj6724] cmd:1
[ 1593.936704] [kdj6724] davinci_mcasp_start(271) stream:1 
[ 1594.057939] [kdj6724] TXTDM_REG     : 0x00000000
arecord: pcm_read:2032: read error: Input/output error[ 1604.208364] [kdj6724] cmd:0
[ 1604.215127] [kdj6724] mcasp_stop_rx(283)
[kdj6724] davinci_mcasp_shutdown(1419)
[ 1604.359540] [kdj6724] TXTDM_REG     : 0x00000000
[ 1604.364288] [kdj6724] evm_shutdown(54)
root@am335x-evm:~#

 


  • The software team have been notified. They will respond here.
  • Hi,

    You hardcode 24 slots, each of them having 32-bits slot_width. What do you set in your dts?

    Best Regards,
    Yordan
  • Hi.

    My device tree is below

    &am33xx_pinmux {
      mcasp0_pins: mcasp0_pins {
        pinctrl-single,pins = < 
                0x1A4 (PIN_INPUT_PULLUP | MUX_MODE0)  /* mcasp0_fsr.mcasp0_fsr */
                0x1A8 (PIN_INPUT_PULLDOWN | MUX_MODE0)  /* mcasp0_axr1.mcasp0_axr1 */
                0x1A0 (PIN_INPUT_PULLUP | MUX_MODE0) /* mcasp0_aclkr.mcasp0_aclkr */
        >;
      };
    };
    
    &mcasp0 {
      #sound-dai-cells = <0>;
      pinctrl-names = "default";
      pinctrl-0 = <&mcasp0_pins>;
      status = "okay";
      op-mode = <0>;  /* MCASP_IIS_MODE */
      tdm-slots = <2>;
      serial-dir = <  /* 0: INACTIVE, 1: TX, 2: RX */
          0 2 0 0
        >;
      tx-num-evt = <32>;
      rx-num-evt = <32>;
    };
    
    sound0:sound@0 {
            compatible = "ti,pcm5102a-evm-audio-in";
            ti,model = "TI PCM5102A";
            ti,audio-codec = <&pcm5102a>;
            ti,mcasp-controller = <&mcasp0>;
            ti,codec-clock-rate = <24000000>;
        };
    
    

    And I found something that can not understand so I attach more detail 

    this is connection between BT and AM3352. BT is operated as master, AM3352 is slave.

    AM3352 receive clock configuration is

    In this figure I think ASYNC value would be set. But "mcasp_i2s_hw_param() (davinci-mcasp.c)" function always make ASYNC value clear.

    I do not understand why. Is it ok to change mcasp_clr_bits to mcasp_set_bits.  (Line 48)

    static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
                int channels)
    {
      int i, active_slots;
      int total_slots;
      int active_serializers;
      u32 mask = 0; 
      u32 busel = 0; 
    
      total_slots = mcasp->tdm_slots;
    
        printk("[kdj6724] %s(%d) stream:%d channels:%d total_slots:%d\n", 
                __FUNCTION__, __LINE__, stream, channels, total_slots);
      /*
       * If more than one serializer is needed, then use them with
       * all the specified tdm_slots. Otherwise, one serializer can
       * cope with the transaction using just as many slots as there
       * are channels in the stream.
       */
      if (mcasp->tdm_mask[stream]) {
        active_slots = hweight32(mcasp->tdm_mask[stream]);
        active_serializers = (channels + active_slots - 1) / 
          active_slots;
            printk("[kdj6724] %s(%d) active_slots:%d active_serializers:%d\n", 
                    __FUNCTION__, __LINE__, active_slots, active_serializers);
        if (active_serializers == 1) { 
          active_slots = channels;
          for (i = 0; i < total_slots; i++) {
            if ((1 << i) & mcasp->tdm_mask[stream]) {
              mask |= (1 << i);
              if (--active_slots <= 0)
                break;
            }    
          }    
        }    
      } else {
        active_serializers = (channels + total_slots - 1) / total_slots;
        if (active_serializers == 1)
          active_slots = channels;
        else 
          active_slots = total_slots;
    
            printk("[kdj6724] %s(%d) active_slots:%d active_serializers:%d\n", 
                    __FUNCTION__, __LINE__, active_slots, active_serializers);
        for (i = 0; i < active_slots; i++) 
          mask |= (1 << i);
      }
      mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC);
      if (!mcasp->dat_port)
        busel = TXSEL;
    
      if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
            printk("[kdj6724] %s(%d) 0x%08x\n", __FUNCTION__, __LINE__, mask);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
        mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
        mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
                 FSXMOD(total_slots), FSXMOD(0x1FF));
      } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
            printk("[kdj6724] %s(%d) 0x%08x\n", __FUNCTION__, __LINE__, mask);
        mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
        mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
        mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
                 FSRMOD(total_slots), FSRMOD(0x1FF));
        /*
         * If McASP is set to be TX/RX synchronous and the playback is
         * not running already we need to configure the TX slots in
         * order to have correct FSX on the bus
         */
        if (mcasp_is_synchronous(mcasp) && !mcasp->channels)
          mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
                   FSXMOD(total_slots), FSXMOD(0x1FF));
      }
    
      return 0;
    }

    - MCASP register dump result

    [ 63.744369] [kdj6724] TXFMCTL_REG : 0x00000010
    [ 63.749004] [kdj6724] RXFMCTL_REG : 0x00000c10
    [ 63.753639] [kdj6724] TXFMT_REG : 0x000000f6
    [ 63.758274] [kdj6724] RXFMT_REG : 0x000080f2
    [ 63.762910] [kdj6724] ACLKXCTL_REG : 0x0018000a
    [ 63.767545] [kdj6724] ACLKRCTL_REG : 0x0000000a
    [ 63.772181] [kdj6724] AHCLKXCTL_REG : 0x00188000
    [ 63.776816] [kdj6724] AHCLKRCTL_REG : 0x00008000
    [ 63.781450] [kdj6724] PDIR_REG : 0x00000000
    [ 63.786086] [kdj6724] RXMASK_REG : 0x00ffffff
    [ 63.790722] [kdj6724] TXMASK_REG : 0x00ffffff
    [ 63.795357] [kdj6724] RXTDM_REG : 0x00000003
    [ 63.799991] [kdj6724] TXTDM_REG : 0x00000000

  • Hi,

    I'll have a look at the register settings to see if I can provide something else.
    But as a first glance, I see that you set tdm-slots = <2> and in tdm mode you can assign up to 32 slots per serializer. So try matching the hardcoded value of 24 slots in your driver with dts. That is try setting tdm-slots = <24>;

    Best Regards,
    Yordan
  • As for replacing mcasp_clr_bits with mcasp_set_bits.. this is not a good idea.
    You can try adding the setting of ASYNC later in the different conditions in the driver, but IMO you shouldn't replace line 48.

    Best Regards,
    Yordan
  • I don't know this is possible combination to record through MCASP.
    I mean, AM3352 MCASP support my BT bit format.

    thank you.
  • Part Number: AM3352

    Tool/software: Linux

    Hi.

     I am trying to record I2S data. I have record problem. The problem is record data has a lot of noise or no valid data.

    I have checked several point to fix it. I found something strange thing. Please check this.

    my block diagram is this.

    So I did MCASP clock configuration like this

    The problem is ASYNC bit configuration in MCASP0 side. I want to use separately RX clock and TX clock.

    So When I set ASYNC bit(Asynchronous), RSRCLR(GBLCTL) bit is never set. In fact in davinci-mcasp.c alaway clear ASYNC(Synchronous), I do not know why.

    I want to know, is there any problems with my  structure using different MCASP part RX and TX.

    thank you