i.MXRT600 as normal I2S slave does not work with external SCK

cancel
Showing results for 
Search instead for 
Did you mean: 

i.MXRT600 as normal I2S slave does not work with external SCK

Jump to solution
307 Views
alborgMB
Contributor II

I'm trying to interface my MIMXRT685-EVK with an Analog Devices ADC. The latter uses I2S to stream data and provides the FrameSync(WS) and Clock (SCK) signal in addition to SDA.

Consequently I need to configure the RT600 as an I2S slave. I have configured Flexcomm 5 as a normal I2S slave which relies on an external clock.

The Clocks, Pins and Peripherals wizard within MCUXpresso is used for the configuration and generation of peripheral driver code.

However, no data is received by the I2S interface. I have in both DMA and Interrupt-driven transfer modes.

During debugging, I noticed that there is no change in the I2S5 peripheral registers, beyond the changes made during configuration. No changes were observed in the FIFO, status and interrupt related registers.

I have verified the functionality of the ADC through a logic analyzer. It is working.

The SDK examples for I2S (record and playback - both DMA and interrupt) work on my eval board.

I have double-checked the I2S (Flexcomm 5 ) pin mapping from the schematic just to be sure.

Is there some critical prerequisite or intermediary step that I am dorgetting which needs to be carried out in order for the Flexcomm to function with an external SCK?

Note: SCK clock provided by ADC is 4 MHz.

I am pasting some code snippets related to the configuration of Flexcomm5 as an I2S slave.

Pin configuration:

 

void BOARD_InitPins(void)
{

    const uint32_t port1_pin3_config = (/* Pin is configured as FC5_SCK */
                                        IOPCTL_PIO_FUNC1 |
                                        /* Disable pull-up / pull-down function */
                                        IOPCTL_PIO_PUPD_DI |
                                        /* Enable pull-down function */
                                        IOPCTL_PIO_PULLDOWN_EN |
                                        /* Disable input buffer function */
                                        IOPCTL_PIO_INBUF_DI |
                                        /* Normal mode */
                                        IOPCTL_PIO_SLEW_RATE_NORMAL |
                                        /* Normal drive */
                                        IOPCTL_PIO_FULLDRIVE_DI |
                                        /* Analog mux is disabled */
                                        IOPCTL_PIO_ANAMUX_DI |
                                        /* Pseudo Output Drain is disabled */
                                        IOPCTL_PIO_PSEDRAIN_DI |
                                        /* Input function is not inverted */
                                        IOPCTL_PIO_INV_DI);
    /* PORT1 PIN3 (coords: G16) is configured as FC5_SCK */
    IOPCTL_PinMuxSet(IOPCTL, 1U, 3U, port1_pin3_config);

    const uint32_t port1_pin4_config = (/* Pin is configured as FC5_TXD_SCL_MISO_WS */
                                        IOPCTL_PIO_FUNC1 |
                                        /* Disable pull-up / pull-down function */
                                        IOPCTL_PIO_PUPD_DI |
                                        /* Enable pull-down function */
                                        IOPCTL_PIO_PULLDOWN_EN |
                                        /* Disable input buffer function */
                                        IOPCTL_PIO_INBUF_DI |
                                        /* Normal mode */
                                        IOPCTL_PIO_SLEW_RATE_NORMAL |
                                        /* Normal drive */
                                        IOPCTL_PIO_FULLDRIVE_DI |
                                        /* Analog mux is disabled */
                                        IOPCTL_PIO_ANAMUX_DI |
                                        /* Pseudo Output Drain is disabled */
                                        IOPCTL_PIO_PSEDRAIN_DI |
                                        /* Input function is not inverted */
                                        IOPCTL_PIO_INV_DI);
    /* PORT1 PIN4 (coords: G17) is configured as FC5_TXD_SCL_MISO_WS */
    IOPCTL_PinMuxSet(IOPCTL, 1U, 4U, port1_pin4_config);

    const uint32_t port1_pin5_config = (/* Pin is configured as FC5_RXD_SDA_MOSI_DATA */
                                        IOPCTL_PIO_FUNC1 |
                                        /* Disable pull-up / pull-down function */
                                        IOPCTL_PIO_PUPD_DI |
                                        /* Enable pull-down function */
                                        IOPCTL_PIO_PULLDOWN_EN |
                                        /* Disable input buffer function */
                                        IOPCTL_PIO_INBUF_DI |
                                        /* Normal mode */
                                        IOPCTL_PIO_SLEW_RATE_NORMAL |
                                        /* Normal drive */
                                        IOPCTL_PIO_FULLDRIVE_DI |
                                        /* Analog mux is disabled */
                                        IOPCTL_PIO_ANAMUX_DI |
                                        /* Pseudo Output Drain is disabled */
                                        IOPCTL_PIO_PSEDRAIN_DI |
                                        /* Input function is not inverted */
                                        IOPCTL_PIO_INV_DI);
    /* PORT1 PIN5 (coords: J16) is configured as FC5_RXD_SDA_MOSI_DATA */
    IOPCTL_PinMuxSet(IOPCTL, 1U, 5U, port1_pin5_config);
}

 

Peripheral Initialization:

 

// Called within BOARD_InitBootPeripherals function
void BOARD_InitPeripherals(void)
{
  /* Global initialization */
  DMA_Init(DMA0_DMA_BASEADDR);

  /* Initialize components */
  FLEXCOMM5_init();
}

 

I2S Configuration:

 

const i2s_config_t FLEXCOMM5_config = {
  .masterSlave = kI2S_MasterSlaveNormalSlave,
  .mode = kI2S_ModeDspWsShort,
  .rightLow = false,
  .leftJust = false,
  .sckPol = true,
  .wsPol = true,
  .divider = 1,
  .oneChannel = true,
  .dataLength = 32,
  .frameLength = 32,
  .position = 0,
  .watermark = 7,
  .txEmptyZero = false,
  .pack48 = false
};
dma_handle_t FLEXCOMM5_RX_Handle;
i2s_dma_handle_t FLEXCOMM5_Rx_DMA_Handle;

 

 Flexcomm Configuration:

 

static void FLEXCOMM5_init(void) {
  /* Flexcomm I2S initialization */
  I2S_RxInit(FLEXCOMM5_PERIPHERAL, &FLEXCOMM5_config);
  /* Enable the DMA 10 channel in the DMA */
  DMA_EnableChannel(FLEXCOMM5_RX_DMA_BASEADDR, FLEXCOMM5_RX_DMA_CHANNEL);
  /* Set the DMA 10 channel priority */
  DMA_SetChannelPriority(FLEXCOMM5_RX_DMA_BASEADDR, FLEXCOMM5_RX_DMA_CHANNEL, kDMA_ChannelPriority1);
  /* Create the DMA FLEXCOMM5_RX_Handle handle */
  DMA_CreateHandle(&FLEXCOMM5_RX_Handle, FLEXCOMM5_RX_DMA_BASEADDR, FLEXCOMM5_RX_DMA_CHANNEL);
  /* Create the I2S DMA handle */
  I2S_RxTransferCreateHandleDMA(FLEXCOMM5_PERIPHERAL, &FLEXCOMM5_Rx_DMA_Handle, &FLEXCOMM5_RX_Handle, RxCallback_Wizard, NULL);
}

 

 This is followed up by defining and pointing to the memory buffer in which the received samples should be stored:

 

s_RxTransfer.data = &s_Buffer;
s_RxTransfer.dataSize = sizeof(s_Buffer);

 

where the buffer was defined as:

 

__ALIGN_BEGIN static uint8_t s_Buffer[DATA_BUFF_LEN] __ALIGN_END;

 

Two DMA receive requests are then enqueued:

 

I2S_RxTransferReceiveDMA(FLEXCOMM5_PERIPHERAL, &FLEXCOMM5_Rx_DMA_Handle, s_RxTransfer);
I2S_RxTransferReceiveDMA(FLEXCOMM5_PERIPHERAL, &FLEXCOMM5_Rx_DMA_Handle, s_RxTransfer);

 

 

The DMA transaction complete handler is defined as:

 

void RxCallback_Wizard(I2S_Type *base,i2s_dma_handle_t *handle,status_t completionStatus,void *userData)
{
	i2s_transfer_t transfer;
	/* Enqueue the same original buffer all over again */
	if (completionStatus == kStatus_I2S_BufferComplete)
	{
		transfer.data = &s_Buffer;
		transfer.dataSize = sizeof(s_Buffer);
		I2S_RxTransferReceiveDMA(base, handle, transfer);
	}
}

 

Picture of I2S stream captured via a Logic Analyzer:

alborgMB_0-1647856860162.png

 

Labels (1)
0 Kudos
1 Solution
204 Views
alborgMB
Contributor II

It was an issue with the pin mode configuration. The input buffers of the pins were disabled.

 

However the data from the ADC is not being read properly. I believe I have configured the DMA correctly but I will try data receipt in interrupt mode as well.

 

View solution in original post

0 Kudos
4 Replies
269 Views
alborgMB
Contributor II

The following diagram illustrates the interace between the Flexcomm 5 interface and the ADC. The i.MX RT 600 is supposed to function as an I2S slave.

FlexComm 5 I2S interface.png

0 Kudos
234 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

As first step,  I suggest you use interrupt mode for the I2S slave  to receive the data from ADC, after the rt600 has received the data correctly, then add the DMA code.

BTW, can you tell us the ADC part number and the mode of the ADC so that we can check if the I2S configuration is correct.

BR

XiangJun Rong

0 Kudos
205 Views
alborgMB
Contributor II

It was an issue with the pin mode configuration. The input buffers of the pins were disabled.

 

However the data from the ADC is not being read properly. I believe I have configured the DMA correctly but I will try data receipt in interrupt mode as well.

 

0 Kudos
230 Views
alborgMB
Contributor II

Thanks for the response @xiangjun_rong ,

 

I have tried I2S interrupt mode configuration as well. There is no data receipt.

 

During runtime debugging I noticed that beyond changes made to the I2S5 registers during I2S configuration, there are no changes observed in the FIFO, status and interrupt related registers.

 

It is as if the I2S Flexcomm5 interface isn't running at all. I suspect that this is some clock related issue. 

When a Flexcomm interface is configured as a normal I2S slave, does it require any additional clock signal (other than the external SCK provided by the I2S master) to function? I don't think it does, but I just want to be sure.

Is any additional specific clock or signal routing configuration required?

----------------------------------------------------

I'm using the Analog Devices AD7768 ADC since I possess its Eval board. It's an 8 channel ADC, and based on default configuration, it acts as a clock master with 8 data signals for each ADC channel and corresponding data clock (SCK) abd Frame Sync (WS) signals.

Given the configuration, the AD7768 is a conventional I2S master for a single interface if I only connect one data channel (DOUT0).

For the default configuration:

SCK: 4 MHz

1/Output data rate: 1.024ms. (1/ODR is the time between each short high pulse) (This is the short WS pulse).

SDA: (DOUT0) Data embedded in SDA for 32 clock pulses following WS high.

alborgMB_0-1648457910170.png

 

Datasheet AD7768

AD7768 Eval board User guide 

0 Kudos