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.

EK-TM4C123GXL: EK-TM4C123GXL during send SPI data than have on Analog input rms -30db noise

Part Number: EK-TM4C123GXL

I need to use all 4 SPI data connections.

When the data is sending over SPI, than the noise during sampling a analog input is very much increasing to rms -30db.

Is that a common issue ?

  • Hi,

      I'm not clear as what you are trying to do. Are you saying you are using a SPI with 4 pins while you use the ADC to sample an analog input? Noise got coupled into the ADC input when SPI pins are running?

  • I use 4 SPI GPIO pins to send data.
    I have configured them as follows:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #define SSI_CLOCK (4800000)
    void init_SSI0()
    {
    // enable SSI1 Tx PA5 only
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_SSI0));
    // port config
    MAP_GPIOPinConfigure(GPIO_PA5_SSI0TX);
    MAP_GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5);
    MAP_GPIOPadConfigSet(GPIO_PORTA_BASE, GPIO_PIN_5,
    GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD);
    // SSI config
    MAP_IntDisable(INT_SSI0);
    MAP_SSIIntDisable(SSI0_BASE, SSI_TXFF | SSI_RXFF | SSI_RXTO | SSI_RXOR);
    MAP_SSIDisable(SSI0_BASE);
    MAP_SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_1,
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    I the uDMA part:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    void init_uDMA_SSI0()
    {
    // signal 0
    // uDMA Channel 11
    MAP_SSIDMADisable(SSI0_BASE, SSI_DMA_RX | SSI_DMA_TX);
    MAP_uDMAChannelAssign(UDMA_CH11_SSI0TX);
    MAP_uDMAChannelAttributeDisable(11,
    UDMA_ATTR_ALTSELECT |
    UDMA_ATTR_HIGH_PRIORITY |
    UDMA_ATTR_REQMASK |
    UDMA_ATTR_USEBURST);
    MAP_uDMAChannelControlSet(11 | UDMA_PRI_SELECT,
    UDMA_SIZE_8 | UDMA_SRC_INC_8 |
    UDMA_DST_INC_NONE | UDMA_ARB_4);
    MAP_uDMAChannelControlSet(11 | UDMA_ALT_SELECT,
    UDMA_SIZE_8 | UDMA_SRC_INC_8 |
    UDMA_DST_INC_NONE | UDMA_ARB_4);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    i send the data with uDMA over SPI. the data is prepared in the sram.

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    void start_uDMA_SSI0()
    {
    MAP_uDMAChannelTransferSet(11 | UDMA_PRI_SELECT,
    UDMA_MODE_PINGPONG, &uDMABufferSSI0_PRI,
    (void *)(SSI0_BASE + SSI_O_DR),
    SSI_TRANSFERSIZE);
    MAP_uDMAChannelEnable(11 | UDMA_PRI_SELECT);
    uDMABufferStateSSI0_PRI = EMPTYING;
    uDMABufferModeSSI0 = PING;
    MAP_uDMAChannelTransferSet(11 | UDMA_ALT_SELECT,
    UDMA_MODE_PINGPONG, &uDMABufferSSI0_ALT,
    (void *)(SSI0_BASE + SSI_O_DR),
    SSI_TRANSFERSIZE);
    MAP_uDMAChannelEnable(11 | UDMA_ALT_SELECT);
    uDMABufferStateSSI0_ALT = EMPTYING;
    uDMABufferModeSSI0 = PONG;
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    then i start the 4 SPI streams together:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    void startDMABufferSSI()
    {
    start_uDMA_SSI0();
    MAP_SysCtlDelay(70);
    start_uDMA_SSI1();
    MAP_SysCtlDelay(70);
    start_uDMA_SSI2();
    MAP_SysCtlDelay(70);
    start_uDMA_SSI3();
    resetCode = 1;
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    The small delay is imported because it could be that ss1 stops before the sending is finished.

    I don't know why, but that's another problem.

    when the data sending is finished than the new data will be prepared and the the sending starts again in a loop.

    here are the Interrupts Handlers

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    void uDMASSI0IntHandler(void)
    {
    MAP_SSIIntClear(SSI0_BASE, SSI_RXTO | SSI_RXOR); // Do I have to do that?
    MAP_uDMAIntClear(11); // Do I have to do that?
    if (MAP_uDMAChannelModeGet(11 | UDMA_PRI_SELECT) == UDMA_MODE_STOP)
    {
    uDMABufferStateSSI0_PRI = EMPTY;
    }
    if (MAP_uDMAChannelModeGet(11 | UDMA_ALT_SELECT) == UDMA_MODE_STOP)
    {
    uDMABufferStateSSI0_ALT = EMPTY;
    }
    }
    void uDMASSI1IntHandler(void)
    {
    MAP_SSIIntClear(SSI1_BASE, SSI_RXTO | SSI_RXOR); // Do I have to do that?
    MAP_uDMAIntClear(25); // Do I have to do that?
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    parallel to sending the data via SPI, an analog input is also recorded.

    the trigger comes from a timer

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #define ADC_SAMPLING_RATE (44100)
    void init_TIMER_2()
    {
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2);
    while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER2));
    // Timer 2A is PB0 trigger for ADC0 SS3
    // Timer 2B is PB1 not used
    MAP_TimerConfigure(TIMER2_BASE, TIMER_CFG_SPLIT_PAIR |
    TIMER_CFG_A_PERIODIC | TIMER_CFG_B_ONE_SHOT);
    // Timer 2A
    // set ADC0 SS3 sampling rate
    MAP_TimerLoadSet(TIMER2_BASE, TIMER_A,
    (SysCtlClockGet()/ADC_SAMPLING_RATE) - 1);
    // Timer 2A
    // enable the ADC trigger output for Timer A.
    MAP_TimerControlTrigger(TIMER2_BASE, TIMER_A, true);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    recording with uDMA

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    void init_uDMA_MIC0()
    {
    // adc mic setup
    // uDMA Channel 17
    MAP_uDMAChannelAssign(UDMA_CH17_ADC0_3);
    MAP_uDMAChannelAttributeDisable(17,
    UDMA_ATTR_ALTSELECT |
    UDMA_ATTR_HIGH_PRIORITY |
    UDMA_ATTR_REQMASK);
    MAP_uDMAChannelControlSet(17 | UDMA_PRI_SELECT,
    UDMA_SIZE_16 | UDMA_SRC_INC_NONE |
    UDMA_DST_INC_16 | UDMA_ARB_1);
    MAP_uDMAChannelControlSet(17 | UDMA_ALT_SELECT,
    UDMA_SIZE_16 | UDMA_SRC_INC_NONE |
    UDMA_DST_INC_16 | UDMA_ARB_1);
    MAP_uDMAChannelAttributeEnable(17, UDMA_ATTR_USEBURST);
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    adc setup is:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    void init_ADC0()
    {
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    while(!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_ADC0));
    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PIOSC |
    ADC_CLOCK_RATE_HALF, 1);
    SysCtlDelay(10);
    }
    void init_ADC0_MIC0()
    {
    MAP_GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_2);
    MAP_IntDisable(INT_ADC0SS3);
    MAP_ADCIntDisable(ADC0_BASE, 3);
    MAP_ADCSequenceDisable(ADC0_BASE, 3);
    MAP_ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_TIMER, 0);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    start the uDMA channels:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    void start_uDMA_ADC0_SS3()
    {
    if (mic0BufferState_PRI == EMPTY)
    {
    MAP_uDMAChannelTransferSet(17 | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG,
    (void *)(ADC0_BASE + ADC_O_SSFIFO3),
    &mic0Buffer_PRI, ADC_SAMPLES);
    MAP_uDMAChannelEnable(17 | UDMA_PRI_SELECT);
    mic0BufferState_PRI = FILLING;
    }
    if (mic0BufferState_ALT == EMPTY)
    {
    MAP_uDMAChannelTransferSet(17 | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG,
    (void *)(ADC0_BASE + ADC_O_SSFIFO3),
    &mic0Buffer_ALT, ADC_SAMPLES);
    MAP_uDMAChannelEnable(17 | UDMA_ALT_SELECT);
    mic0BufferState_ALT = FILLING;
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    start stop the ss3

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    void start_ADC0_SS3()
    {
    MAP_ADCSequenceEnable(ADC0_BASE, 3);
    MAP_ADCIntClear(ADC0_BASE, 3);
    MAP_ADCSequenceOverflowClear(ADC0_BASE, 3);
    MAP_ADCSequenceUnderflowClear(ADC0_BASE, 3);
    MAP_ADCSequenceDMAEnable(ADC0_BASE, 3);
    MAP_ADCIntEnable(ADC0_BASE, 3); // Do I have to do that?
    MAP_IntEnable(INT_ADC0SS3); // Do I have to do that?
    MAP_TimerEnable(TIMER2_BASE, TIMER_A);
    }
    void stop_ADC0_SS3()
    {
    MAP_TimerDisable(TIMER2_BASE, TIMER_A);
    MAP_IntDisable(INT_ADC0SS3);
    MAP_ADCIntDisable(ADC0_BASE, 3);
    MAP_ADCSequenceDisable(ADC0_BASE, 3);
    MAP_ADCSequenceOverflowClear(ADC0_BASE, 3);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    and the record start again and in loop. normaly i dont use the function stop_ADC0_SS3()

    here are the interrupt handler

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    void ADC0SS3IntHandler(void)
    {
    MAP_ADCIntClear(ADC0_BASE, 3); // Do I have to do that?
    MAP_uDMAIntClear(17); // Do I have to do that?
    if (MAP_uDMAChannelModeGet(17 | UDMA_PRI_SELECT) == UDMA_MODE_STOP)
    {
    mic0BufferState_PRI = FULL;
    }
    if (MAP_uDMAChannelModeGet(17 | UDMA_ALT_SELECT) == UDMA_MODE_STOP)
    {
    mic0BufferState_ALT = FULL;
    }
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    every time data is sent over spi there is a strong noise in the samples.

  • Hi,

      Although I can't really solve any noise issues for you, I have a few comments that might contribute to the noises you are seeing. 

      - I see you are running 4 SPI modules at 4.8Mhz. This can create SSO (simultaneous switching output) which can draw quite some currents and affects the voltage supply. Proper decoupling caps and placement of them is critical for high speed operations.

    #define SSI_CLOCK (4800000)

      - You are using the LaunchPad board. The LaunchPad has VDDA for ADC tied to VDD for simplicity. In another word, any noise on the digital supply can couple to the analog supply for ADC which will affect ADC accuracy. If you were to design your own board, I will suggest you split the supplies to digital and analog domains. ADC VREFP and VREFN are connected to VDDA and GNDA internally. Any noises or ripples on the VDD/GND will follow VREF and hence the accuracy. 

      - I see you use CH5 for ADC. If you are willing to do an experiment you can try a different ADC channel perhaps with the pin that is far away from the SSI modules or reduce the SSI_CLOCK speed to see if it alleviates your finding. Other than that, I have not much left to offer. 

    MAP_ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH5 | ADC_CTL_IE |
    ADC_CTL_END);

    When you create your own design, please go through section 4.5 for ADC design considerations as well as the rest of the document for best design practices. 

    https://www.ti.com/lit/pdf/spma059

  • I have just tested it. it makes hardly any difference if I send with only one SSI or with 2 or with 3 or with 4. the noise is already present with one data transfer and is amplified by each further data transfer by approx. 5-6dB.

  • I have another EK-TM4C123GXL.
    If I use one board for the SPI transmission and the other for the recording of the samples. Can I then separate both boards from one another so that the noise is not transmitted?
    But I need a data interface between the boards. So that I can transfer data. And I need between the boards 3-5 GPIO ports as input or output.

  • Hi,

    If I use one board for the SPI transmission and the other for the recording of the samples. Can I then separate both boards from one another so that the noise is not transmitted?

    I think that will help but I believe having a split power rails with VDDA a dedicated supply to ADC will give you the best performance. Don't you plan to design your own board eventually?

    3.5.4 Splitting Power Rails and Grounds

    TivaTm C Series microcontrollers are designed to operate with VDD and VDDA pins connected directly to the same +3.3V power source. Some applications may justify separation of VDDA from VDD to allow insertion of a filter to improve analog performance. Before deciding to split these power rails, the power architecture of the device should be reviewed to determine which on-chip modules are powered by each supply. The device data sheet contains a drawing that shows power architecture. Filter options include filter capacitors in conjunction with either a low-value resistor or inductor/ferrite bead to form a low-pass filter. If the VDD and VDDA pins are split, the designer must ensure that VDDA power is applied before or simultaneously with VDD and that VDDA is removed after or simultaneously with VDD. If VDDA is to be selected as a reference source for the ADC, the ADC will achieve better performance when powered with a separate VDDA power rail and filtered with a 0.01uF and 1uF capacitor (CREF) between VDDA and GNDA. The GND and GNDA pins should always be connected together—preferably to a solid ground plane or copper pour.

    Please also check if your PC is providing a stable 5V to the board. Will a different PC or a different USB ports on the same PC make a difference?

  • Please also check if your PC is providing a stable 5V to the board. Will a different PC or a different USB ports on the same PC make a difference?

    I dont use the usb from a pc as power supply. i use a 230V to 5V powersupply from https://www.meanwell.com/productPdf.aspx?i=410#1
    Mean Well RS 100-5.

    Don't you plan to design your own board eventually?

    Not yet.

    I started embedded programming 2 years ago. And I enjoy it. My next goal will be to go deeper into DSP. For this I bought this book:

    bcs.wiley.com/.../Books
    It uses exactly this board.
    The board with the audio codec is in the rebuild.
    This is also the reason why it is not bad for me to use 2 boards.
    But also in this book he uses 2 SSI to build an I2S data transfer. I find this also very interesting.

    But again my question. It doesn't matter if one or four SSI are used at 4.8Mhz. Is there always such a noise when SSI is used?
    Or is that just because I am using a transmit line and abusing the SSI connection that way?

  • All I can say is that crosstalk varies with transmission frequency, with higher frequencies creating more interference. I would have expected at lower SPI clock frequency, any noise induced on ADC SPI from SPI will be reduced. The accuracy of ADC will be affected by how VDDA is sourced and noise on single-ended input from the nearby digital traces. Single-ended inputs are more sensitive to board and trace noise than differential inputs. Single-ended inputs are highly dependent on how clean the board layout is designed. If the input signal is not well-isolated on the board, higher noise could potentially be seen at the ADC output. As I have already suggested you can improve the ADC accuracy by splitting VDDA for ADC and you can use the differential ADC mode. As for the LaunchPad, it is what it is today.