Data distortion STM324l micro is host to A2B bus (AD2428)

Hello,

I am currently using a STM32L4 micro as a host to the AD2428 master transceiver with one AD2428 slave node. I made use of Sigma studio to generate the bus configuration C file (attached) and make use of the SAI on the STM micro to acquire data in master receiver mode. It is in TDM4 mode with a slot size of 16.

Including other files from the example project, discovery works and I manage to get data coming through via SAI DMA after I relay to my PC host via UART. However, there seems to be distortion of the signal (original signal is a 1 khz Sine wave). I want to check if my SAI settings on the MCU end is correct:

Protocol: I2S MSB justified.

Data size: 16 bits.   

Number of slots: 4

Master clock: enabled.

Audio frequency: 48 kHz

Fifo threshold: empty

Output drive: Disabled.

I left the other settings as default - I am using a STM32 Cube IDE. The funny thing is that some good data comes through but they are positioned in odd locations in the DMA buffer i.e. data which I expect in slot 0 and 1 are found in slots 1 and 2 in the DMA buffer (in a repeating pattern).

Please help me to check if my SAI settings are correct and any other register settings I need to make in order to make it work. Any ideas about where the problem might be will be appreciated. 

Thanks very much,

Ed 

  • Hi, the configuration file is too large so I share the auto-generated i2c command list here instead. Thanks.

    ADI_A2B_DISCOVERY_CONFIG gaA2BConfig[CONFIG_LEN] =
    {
    	{0x68u,	WRITE,	0x12u,	0x84u},	/* CONTROL */
    	{0x00u,	DELAY,	0x00u,	0x19u},	/* A2B_Delay */
    	{0x68u,	READ,	0x17u,	0x00u},	/* INTTYPE */
    	{0x68u,	WRITE,	0x1Bu,	0x77u},	/* INTMSK0 */
    	{0x68u,	WRITE,	0x1Cu,	0x78u},	/* INTMSK1 */
    	{0x68u,	WRITE,	0x1Du,	0x0Fu},	/* INTMSK2 */
    	{0x68u,	WRITE,	0x0Fu,	0x77u},	/* RESPCYCS */
    	{0x68u,	WRITE,	0x12u,	0x01u},	/* CONTROL */
    	{0x68u,	WRITE,	0x41u,	0xB1u},	/* I2SGCFG */
    	{0x68u,	WRITE,	0x09u,	0x01u},	/* SWCTL */
    	{0x68u,	WRITE,	0x13u,	0x77u},	/* DISCVRY */
    	{0x00u,	DELAY,	0x00u,	0x32u},	/* A2B_Delay */
    	{0x68u,	READ,	0x1Au,	0x00u},	/* INTPND2 */
    	{0x68u,	WRITE,	0x1Au,	0x01u},	/* INTPND2 */
    	{0x68u,	WRITE,	0x01u,	0x00u},	/* NODEADR */
    	{0x69u,	READ,	0x02u,	0x00u},	/* VENDOR */
    	{0x69u,	READ,	0x03u,	0x00u},	/* PRODUCT */
    	{0x69u,	READ,	0x04u,	0x00u},	/* VERSION */
    	{0x68u,	WRITE,	0x09u,	0x21u},	/* SWCTL */
    	{0x68u,	WRITE,	0x01u,	0x00u},	/* NODEADR */
    	{0x69u,	WRITE,	0x0Au,	0x00u},	/* BCDNSLOTS */
    	{0x69u,	WRITE,	0x0Bu,	0x80u},	/* LDNSLOTS */
    	{0x69u,	WRITE,	0x0Cu,	0x02u},	/* LUPSLOTS */
    	{0x69u,	WRITE,	0x3Fu,	0x01u},	/* I2CCFG */
    	{0x69u,	WRITE,	0x46u,	0x00u},	/* SYNCOFFSET */
    	{0x69u,	WRITE,	0x41u,	0xF0u},	/* I2SGCFG */
    	{0x69u,	WRITE,	0x42u,	0x18u},	/* I2SCFG */
    	{0x69u,	WRITE,	0x43u,	0x00u},	/* I2SRATE */
    	{0x69u,	WRITE,	0x47u,	0x18u},	/* PDMCTL */
    	{0x69u,	WRITE,	0x5Du,	0x00u},	/* PDMCTL2 */
    	{0x69u,	WRITE,	0x48u,	0x00u},	/* ERRMGMT */
    	{0x69u,	WRITE,	0x4Au,	0x10u},	/* GPIODAT */
    	{0x69u,	WRITE,	0x4Du,	0x10u},	/* GPIOOEN */
    	{0x69u,	WRITE,	0x4Eu,	0x00u},	/* GPIOIEN */
    	{0x69u,	WRITE,	0x50u,	0x00u},	/* PINTEN */
    	{0x69u,	WRITE,	0x51u,	0x00u},	/* PINTINV */
    	{0x69u,	WRITE,	0x52u,	0x00u},	/* PINCFG */
    	{0x69u,	WRITE,	0x20u,	0x00u},	/* TESTMODE */
    	{0x69u,	WRITE,	0x59u,	0x00u},	/* CLK1CFG */
    	{0x69u,	WRITE,	0x5Au,	0x41u},	/* CLK2CFG */
    	{0x69u,	WRITE,	0x60u,	0x00u},	/* UPMASK0 */
    	{0x69u,	WRITE,	0x61u,	0x00u},	/* UPMASK1 */
    	{0x69u,	WRITE,	0x62u,	0x00u},	/* UPMASK2 */
    	{0x69u,	WRITE,	0x63u,	0x00u},	/* UPMASK3 */
    	{0x69u,	WRITE,	0x64u,	0x00u},	/* UPOFFSET */
    	{0x69u,	WRITE,	0x65u,	0x00u},	/* DNMASK0 */
    	{0x69u,	WRITE,	0x66u,	0x00u},	/* DNMASK1 */
    	{0x69u,	WRITE,	0x67u,	0x00u},	/* DNMASK2 */
    	{0x69u,	WRITE,	0x68u,	0x00u},	/* DNMASK3 */
    	{0x69u,	WRITE,	0x69u,	0x00u},	/* DNOFFSET */
    	{0x69u,	WRITE,	0x81u,	0x00u},	/* GPIOD0MSK */
    	{0x69u,	WRITE,	0x82u,	0x00u},	/* GPIOD1MSK */
    	{0x69u,	WRITE,	0x83u,	0x00u},	/* GPIOD2MSK */
    	{0x69u,	WRITE,	0x84u,	0x00u},	/* GPIOD3MSK */
    	{0x69u,	WRITE,	0x85u,	0x00u},	/* GPIOD4MSK */
    	{0x69u,	WRITE,	0x86u,	0x00u},	/* GPIOD5MSK */
    	{0x69u,	WRITE,	0x87u,	0x00u},	/* GPIOD6MSK */
    	{0x69u,	WRITE,	0x88u,	0x00u},	/* GPIOD7MSK */
    	{0x69u,	WRITE,	0x8Au,	0x00u},	/* GPIODINV */
    	{0x69u,	WRITE,	0x80u,	0x00u},	/* GPIODEN */
    	{0x69u,	WRITE,	0x90u,	0x00u},	/* MBOX0CTL */
    	{0x69u,	WRITE,	0x96u,	0x00u},	/* MBOX1CTL */
    	{0x69u,	WRITE,	0x5Cu,	0x00u},	/* SUSCFG */
    	{0x69u,	WRITE,	0x58u,	0x00u},	/* I2SRRSOFFS */
    	{0x69u,	WRITE,	0x57u,	0x00u},	/* I2SRRCTL */
    	{0x69u,	WRITE,	0x2Eu,	0x00u},	/* TXACTL */
    	{0x69u,	WRITE,	0x30u,	0x00u},	/* TXBCTL */
    	{0x69u,	WRITE,	0x1Bu,	0x77u},	/* INTMSK0 */
    	{0x69u,	WRITE,	0x1Cu,	0x7Fu},	/* INTMSK1 */
    	{0x69u,	WRITE,	0x1Eu,	0xEFu},	/* BECCTL */
    	{0x68u,	WRITE,	0x3Fu,	0x00u},	/* I2CCFG */
    	{0x68u,	WRITE,	0x42u,	0x19u},	/* I2SCFG */
    	{0x68u,	WRITE,	0x44u,	0x00u},	/* I2STXOFFSET */
    	{0x68u,	WRITE,	0x45u,	0x00u},	/* I2SRXOFFSET */
    	{0x68u,	WRITE,	0x47u,	0x00u},	/* PDMCTL */
    	{0x68u,	WRITE,	0x5Du,	0x00u},	/* PDMCTL2 */
    	{0x68u,	WRITE,	0x48u,	0x00u},	/* ERRMGMT */
    	{0x68u,	WRITE,	0x4Au,	0x00u},	/* GPIODAT */
    	{0x68u,	WRITE,	0x4Du,	0x00u},	/* GPIOOEN */
    	{0x68u,	WRITE,	0x4Eu,	0x00u},	/* GPIOIEN */
    	{0x68u,	WRITE,	0x50u,	0x00u},	/* PINTEN */
    	{0x68u,	WRITE,	0x51u,	0x00u},	/* PINTINV */
    	{0x68u,	WRITE,	0x52u,	0x00u},	/* PINCFG */
    	{0x68u,	WRITE,	0x20u,	0x00u},	/* TESTMODE */
    	{0x68u,	WRITE,	0x59u,	0x00u},	/* CLK1CFG */
    	{0x68u,	WRITE,	0x5Au,	0x00u},	/* CLK2CFG */
    	{0x68u,	WRITE,	0x81u,	0x00u},	/* GPIOD0MSK */
    	{0x68u,	WRITE,	0x82u,	0x00u},	/* GPIOD1MSK */
    	{0x68u,	WRITE,	0x83u,	0x00u},	/* GPIOD2MSK */
    	{0x68u,	WRITE,	0x84u,	0x00u},	/* GPIOD3MSK */
    	{0x68u,	WRITE,	0x85u,	0x00u},	/* GPIOD4MSK */
    	{0x68u,	WRITE,	0x86u,	0x00u},	/* GPIOD5MSK */
    	{0x68u,	WRITE,	0x87u,	0x00u},	/* GPIOD6MSK */
    	{0x68u,	WRITE,	0x88u,	0x00u},	/* GPIOD7MSK */
    	{0x68u,	WRITE,	0x8Au,	0x00u},	/* GPIODINV */
    	{0x68u,	WRITE,	0x80u,	0x00u},	/* GPIODEN */
    	{0x68u,	WRITE,	0x57u,	0x00u},	/* I2SRRCTL */
    	{0x68u,	WRITE,	0x2Eu,	0x00u},	/* TXACTL */
    	{0x68u,	WRITE,	0x30u,	0x00u},	/* TXBCTL */
    	{0x68u,	WRITE,	0x1Eu,	0xEFu},	/* BECCTL */
    	{0x68u,	WRITE,	0x0Du,	0x00u},	/* DNSLOTS */
    	{0x68u,	WRITE,	0x0Eu,	0x02u},	/* UPSLOTS */
    	{0x68u,	WRITE,	0x09u,	0x01u},	/* SWCTL */
    	{0x68u,	WRITE,	0x40u,	0x00u},	/* PLLCTL */
    	{0x68u,	WRITE,	0x01u,	0x80u},	/* NODEADR */
    	{0x69u,	WRITE,	0x40u,	0x00u},	/* PLLCTL */
    	{0x68u,	WRITE,	0x01u,	0x00u},	/* NODEADR */
    	{0x68u,	WRITE,	0x10u,	0x24u},	/* SLOTFMT */
    	{0x68u,	WRITE,	0x11u,	0x02u},	/* DATCTL */
    	{0x68u,	WRITE,	0x56u,	0x00u},	/* I2SRRATE */
    	{0x68u,	WRITE,	0x12u,	0x01u},	/* CONTROL */
    };
    
    #endif /* _ADI_A2B_I2C_LIST_H_ */
    

  • 0
    •  Analog Employees 
    on Aug 11, 2021 4:03 AM

    Hi,

    Can you verify the TDM data on A2B bus is correct?

    Regards,
    Rajarajan

  • Hi Rajarajan,

    I have found out that my problem is due to timing problems on the UART side leading to corruption of the TX buffer and distorting the waveform.

    I have some questions if that's alright.

    1. In a 1 master and 1 slave configuration with the slave outputting audio in 2 channels and sending data upstream (slave in TDM2 mode) to the master and host (master is not contributing anything at all), it makes sense to put the MASTER in TDM2 mode. I was never able to get TDM2 to work though - the minimum seems to be TDM4. Do you know why that is happening?

    2. There is a mention in the technical manual of connecting an accelerometer along with high sampling rate audio devices to the A2B system. I assume that the accelerometer is being polled by an A2B slave in this case by I2C? Can we connect the accelerometer to the master instead of a slave?

    3. Do you have example code for different devices of different sampling rates preferably for an embedded system, but other types of examples are useful too.

    4. In the auto-generated header file containing I2C instructions (from the Sigma Studio UI), I don't think it is as simple as the programming the A2B master/slave registers for discovery and initialisation since it is an interactive process between host MCU, master and slaves? We probably must make use of the discovery.c file for the entire process?

    Thanks very much,

    Ed 

  • 0
    •  Analog Employees 
    on Aug 18, 2021 7:00 AM in reply to lang_zi

    Hi,

    I have listed out my answers below.

    1.When you configure the Master in TDM2 Mode , Please confirm if the Bit Clock frequency is 2 * 32-bit (assuming Channel Size as 32-bit) * 48KHz(Audio Frequency) = 3.072 MHz.

    Also, Please make sure that the I2S/TDM(Sampling and Driving edges) settings between A2B Master and Host MCU are matching. You can verify the A2B_I2SCFG.RXBCLKINV bit.

    2. An Accelerometer is no different to any I2S source connected to A2B. The accelerometer (probably MEMS sensor) converts the X/Y/Z axes data into 3 channel I2S/TDM channels and transmit over A2B. The data is synchronous to A2B and the rate can be configured through I2SRATE register (similar to a codec operating at 24 or 12 kHz). No need of any polling as new samples will be streamed over A2B as per configured sampling rate.

    Most probable use case would be to get accelerometer data from slave side into master side audio DSP to perform ANC/RNC applications. We are not aware of any use case why accelerometer is needed at master side. But technically it is possible to provide the same audio host clock (as provided to A2B master) to accelerometer to get the I2S/TDM data of the 3 axes.

    3. There is no specific example as such , but the local sampling rate of the slave can be programmed to different Sampling rates like  1x, 2x, or 4x of the SYNC Frequency in the A2B_I2SRATE register. Details on how to Program the Sampling Rate can be found in the AD242x Technical reference Manual .

    The Other Example Projects can be found in the Installation Path of A2B Software <Installation Path>\ADI_A2B_Software-Rel19.x.x\Schematics\PC\A2BSchematics

    4. A2B stack (which uses discovery.c) is the interactive process between host, master and slave as you have described. But command list is an alternate/simple solution for low-end micros where the interaction is modelled as delays and I2C writes. One can choose any of the method depending on the requirements.

    Thanks,

    Nandini.

  • Hi Nandini,

    Thanks for the helpful answers.

    I am using 16-bit channels so I suppose that the bit clock should be half of that. But I wasn't able to get it to work when I set my MCU to TDM2 mode. When I tried that on a PC with Audacity running and recording, it didn't work either.

    Best,

    Ed