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-TM4C1294XL: Signal Conversion using ADC161S626 and DAC161S055 EVMs

Part Number: EK-TM4C1294XL
Other Parts Discussed in Thread: ADC161S626EVM

Hello,

My test application is basically takes the input of an analog signal (sine wave from the signal generator) convert it with the ADC161S626EVM BoosterPack and outputs the same signal without any modifications through the DAC161S055EVM BoosterPack, both BoosterPack communicates by the SPI interface.

The problem is that the output signal (Blue) looks like is freezing, like some part of the code is taking too long to be processed.

In the picture from the oscilloscope: Yellow (Output), Blue (Input signal).

The code is bellow. I made function to initialize the ADC and DAC. In main I just call those functions and also made the read/write routine inside while(1).

I'm now sure what exactly could be freezing the code, or taking too long to process. Any help would be very appreciated.

PS.: I tried to use the code highlighter, I hope it worked...

#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/ssi.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"
#include "inc/hw_types.h"

uint32_t ui32SysClkFreq;

uint16_t ui32Index, convertedValue, adcRX[2], value;
uint32_t pui32DataRx[3], complement, dummy;

// Initializing PORTD ==> FSS for the DAC
void InitPORTD(void) {

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);

	while (!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOD)) {
	}

	GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_2);

	GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, GPIO_PIN_2);
}

// Initializing PORTD ==> FSS for the ADC
void InitPORTE(void) {
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

	while (!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOE)) {
	}

	GPIOPinTypeGPIOOutput(GPIO_PORTE_BASE, GPIO_PIN_4);

	GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_4, GPIO_PIN_4);
}

void InitADCSSI() {

	// The SSI0 peripheral must be enabled for use.

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI2);


	// Configure the pin muxing for SSI0 functions on port A2, A3, A4, and A5.

	GPIOPinConfigure(GPIO_PD3_SSI2CLK);
	//GPIOPinConfigure(GPIO_PD2_SSI2FSS);  Function held by PORTE4 (InitPORTE)
	GPIOPinConfigure(GPIO_PD0_SSI2XDAT1);
	GPIOPinConfigure(GPIO_PD1_SSI2XDAT0);


	// Configure the GPIO settings for the SSI pins.  This function also gives
	// control of these pins to the SSI hardware.  Consult the data sheet to
	// see which functions are allocated per pin.
GPIOPinTypeSSI(GPIO_PORTD_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3); SSIConfigSetExpClk(SSI2_BASE, ui32SysClkFreq, SSI_FRF_MOTO_MODE_3, SSI_MODE_MASTER, 5000000, 16); SSIAdvModeSet(SSI2_BASE, SSI_ADV_MODE_LEGACY); // Enable the SSI0 module.
SSIEnable(SSI2_BASE); } void InitDACSSI(void) { //uint32_t pui32DataRx[3]; SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ); SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI3); GPIOPinConfigure(GPIO_PQ0_SSI3CLK); GPIOPinConfigure(GPIO_PQ3_SSI3XDAT1); GPIOPinConfigure(GPIO_PQ2_SSI3XDAT0); GPIOPinTypeSSI(GPIO_PORTQ_BASE, GPIO_PIN_0 | GPIO_PIN_2 | GPIO_PIN_3); SSIConfigSetExpClk(SSI3_BASE, ui32SysClkFreq, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 20000000, 8); SSIEnable(SSI3_BASE); //while (SSIDataGetNonBlocking(SSI2_BASE, &pui32DataRx[0])) { //} } // Initializing the DAC void InitDAC(void) { // Commands to initialing the DAC uint8_t command[2] = { 0x01, 0x28}; uint8_t first_data[2] = { 0x00, 0x00}; uint8_t second_data[2] = { 0x00, 0x00}; uint8_t uintindex; for (uintindex = 0; uintindex < 2; uintindex++) { GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, 0); SSIDataPut(SSI3_BASE, command[uintindex]); while (SSIBusy(SSI3_BASE)) { } SSIDataPut(SSI3_BASE, first_data[uintindex]); while (SSIBusy(SSI3_BASE)) { } SSIDataPut(SSI3_BASE, second_data[uintindex]); while (SSIBusy(SSI3_BASE)) { } GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, GPIO_PIN_2); } } int main(void) { ui32SysClkFreq = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000); InitPORTD(); InitPORTE(); InitADCSSI(); InitDACSSI(); InitDAC(); while (1) { // Emptying the FIFO while (SSIDataGetNonBlocking(SSI2_BASE, &pui32DataRx[0])) {} GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_4, 0); // Reading from the SPI for (ui32Index = 0; ui32Index < 2; ui32Index++) { SSIDataPut(SSI2_BASE, 0x00); SSIDataGet(SSI2_BASE, &dummy); adcRX[ui32Index] = dummy; } GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_4, GPIO_PIN_4); convertedValue = ((adcRX[0] << 2) | (adcRX[1] >> 14)); GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, 0); // Write Command to SPI SSIDataPut(SSI3_BASE, 0x08); while (SSIBusy(SSI3_BASE)) { } SSIDataPut(SSI3_BASE, convertedValue >> 8); while (SSIBusy(SSI3_BASE)) { } SSIDataPut(SSI3_BASE, convertedValue & 0xFF); while (SSIBusy(SSI3_BASE)) { } GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, GPIO_PIN_2); } }

  • I did not see an obvious mistake, but why did you put these lines inside the "while (1)" loop?

    // Emptying the FIFO
    		while (SSIDataGetNonBlocking(SSI2_BASE, &pui32DataRx[0])) {}
    

  • Hello Bob Crosby, thank you for your quick answer.

    I thought that I had to empty the FIFO every time the ADC reads.

    Am I wrong? Do I have to do it just in the first time?

  • Geovani,

    I've had all sorts of problems using SPI and I2C communication if simply relying on while(busy) loops.

        SSIDataPut(SSI3_BASE, 0x08);
        while (SSIBusy(SSI3_BASE)) {}
        SSIDataPut(SSI3_BASE, convertedValue >> 8);
        while (SSIBusy(SSI3_BASE)) {}

    If you look at the signals with a logic analyzer, it appears to me that the second DataPut on the sequence above will happen too soon, right after the first Busy is cleared, but that first busy does not account for an extra "half clock" in the end. In other words, contiguous reads or writes using either SPI or I2C seem to break the clock, and most of the external peripherals respond with invalid values to that situation.

    I actually intended to create a detailed post to discuss this, but for now I'll just throw the issue here as a possible explanation for your problem, as I don't have capture prints available nor the time to arrange a setup these days...

    Second point, your scope print seems to contradict your text, I got confused. You say the output is blue and freezes once in a while, but it is clearly the yellow line that shows an ugly non-sinusoidal pattern.

    Regards

    Bruno

  • Geovani Alves said:
    PS.: I tried to use the code highlighter, I hope it worked...

    It did, and thanks for using it.

    I think your first step needs to be to determine whether your code is 'freezing' or some other effect is occurring.

    The first thing I'd do id to 'scope the chip selects along with your freezing output. See if they stop at the same time as your flat lines.

    Robert

  • Bravo to my poster friend - working in the (always) needed - "Use KISS!"

    His tip to "scope the chip selects" makes great sense - yet so too would be, "Lowering the frequency of your input sine wave." It is always desirable to, "Get something to work - only (then) - "tighten the design screws" - and "Proceed by Refinement."

    All this (firmly) w/in the bounds of KISS - which is sure to provide your best, quickest (and often) only chance for success!
  • Thanks Robert.

    I'll use the 'scope in the CS as soon as I get in the lab again.
  • I did no understand the "working in the (always) needed - "Use KISS!""

    But anyway, thanks for the hint. I'll set low values of frequency and try to scope the CS.

    As soon as I get the results I'll post again.
  • "KISS" is the acronym for following a "Systematic & Simple" process (i.e. Keep it Simple Student/Striver/Success-Seeker.)

    Doing too much - too soon - is a classic means of failure.    In contrast - "KISS" reminds & enforces a simple, measurable procedure - which best insures that (multiple) parts "come together well" as completion nears.   (i.e. each individual element of the design has been independently tested/verified - has received substantial (individual) attention - clearly leading to a complex project's success...

  • I seems that the output got better when I put the:

    // Emptying the FIFO
    while (SSIDataGetNonBlocking(SSI2_BASE, &pui32DataRx[0])) {}

    Inside the function ADCInitSSI().
    So, I slowed down the frequency of the input sine wave, and around 1 kHz it worked fine, no distortion on the output.
    But still, when comes close to 7 KHz sine input, the output gets distorted, and the problem is that I need to sample a wave with at least 40 kHz.

    The Chip Select seems fine.



    
    

    ADC Chip Select:


    DAC Chip Select:

     

    My code haven't changed much, just the highlighted lines:

     

    #include <stdbool.h>
    #include <stdio.h>
    #include <stdint.h>
    #include "inc/hw_memmap.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/ssi.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "utils/uartstdio.h"
    #include "inc/hw_types.h"
    
    uint32_t ui32SysClkFreq;
    
    uint16_t ui32Index, convertedValue, adcRX[2], value;
    uint32_t pui32DataRx[3], complement, dummy;
    
    // Initializing PORTD ==> FSS for the DAC
    void InitPORTD(void) {
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    
    	while (!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOD)) {
    	}
    
    	GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_2);
    
    	GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, GPIO_PIN_2);
    }
    
    // Initializing PORTD ==> FSS for the ADC
    void InitPORTE(void) {
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    
    	while (!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOE)) {
    	}
    
    	GPIOPinTypeGPIOOutput(GPIO_PORTE_BASE, GPIO_PIN_4);
    
    	GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_4, GPIO_PIN_4);
    }
    
    void InitADCSSI() {
    
    	// The SSI0 peripheral must be enabled for use.
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI2);
    
    	// Configure the pin muxing for SSI2 functions on port D0, D1, and D3.
    	GPIOPinConfigure(GPIO_PD3_SSI2CLK);
    	//GPIOPinConfigure(GPIO_PD2_SSI2FSS);  Function held by PORTE4 (InitPORTE)
    	GPIOPinConfigure(GPIO_PD0_SSI2XDAT1);
    	GPIOPinConfigure(GPIO_PD1_SSI2XDAT0);
    
    	GPIOPinTypeSSI(GPIO_PORTD_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3);
    
    	SSIConfigSetExpClk(SSI2_BASE, ui32SysClkFreq, SSI_FRF_MOTO_MODE_3,
    	SSI_MODE_MASTER, 5000000, 16);
    
    	SSIAdvModeSet(SSI2_BASE, SSI_ADV_MODE_LEGACY);
    
    	// Enable the SSI0 module.
    	SSIEnable(SSI2_BASE);
    
    	// Emptying the FIFO
    	while (SSIDataGetNonBlocking(SSI2_BASE, &pui32DataRx[0])) {}
    
    }
    
    void InitDACSSI(void) {
    
    	//uint32_t pui32DataRx[3];
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI3);
    
    	GPIOPinConfigure(GPIO_PQ0_SSI3CLK);
    	GPIOPinConfigure(GPIO_PQ3_SSI3XDAT1);
    	GPIOPinConfigure(GPIO_PQ2_SSI3XDAT0);
    
    	GPIOPinTypeSSI(GPIO_PORTQ_BASE, GPIO_PIN_0 | GPIO_PIN_2 | GPIO_PIN_3);
    
    	SSIConfigSetExpClk(SSI3_BASE, ui32SysClkFreq, SSI_FRF_MOTO_MODE_0,
    	SSI_MODE_MASTER, 20000000, 8);
    
    	SSIEnable(SSI3_BASE);
    
    	while (SSIDataGetNonBlocking(SSI3_BASE, &pui32DataRx[0])) {}
    
    }
    
    // Initializing the DAC
    void InitDAC(void) {
    
    	// Commands to initialing the DAC
    	uint8_t command[2] = { 0x01, 0x28};
    	uint8_t first_data[2] = { 0x00, 0x00};
    	uint8_t second_data[2] = { 0x00, 0x00};
    	uint8_t uintindex;
    
    	for (uintindex = 0; uintindex < 2; uintindex++) {
    
    		GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, 0);
    
    		SSIDataPut(SSI3_BASE, command[uintindex]);
    		while (SSIBusy(SSI3_BASE)) {
    		}
    
    		SSIDataPut(SSI3_BASE, first_data[uintindex]);
    		while (SSIBusy(SSI3_BASE)) {
    		}
    		SSIDataPut(SSI3_BASE, second_data[uintindex]);
    		while (SSIBusy(SSI3_BASE)) {
    		}
    
    		GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, GPIO_PIN_2);
    
    	}
    
    }
    
    int main(void) {
    
    	ui32SysClkFreq = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
    	SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
    	SYSCTL_CFG_VCO_480), 120000000);
    
    	InitPORTD();
    
    	InitPORTE();
    
    	InitADCSSI();
    
    	InitDACSSI();
    
    	InitDAC();
    
    	while (1) {
    
    
    
    		GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_4, 0);
    
    
    		// Reading from the SPI
    		for (ui32Index = 0; ui32Index < 2; ui32Index++) {
    
    			SSIDataPut(SSI2_BASE, 0x00);
    
    			SSIDataGet(SSI2_BASE, &dummy);
    
    			adcRX[ui32Index] = dummy;
    
    		}
    
    		while (SSIDataGetNonBlocking(SSI2_BASE, &pui32DataRx[0])) {}
    
    		GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_4, GPIO_PIN_4);
    
    		convertedValue = ((adcRX[0] << 2) | (adcRX[1] >> 14));
    
    		GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, 0);
    
    		// Write Command to SPI
    		SSIDataPut(SSI3_BASE, 0x08);
    		while (SSIBusy(SSI3_BASE)) {
    		}
    		SSIDataPut(SSI3_BASE, convertedValue >> 8);
    		while (SSIBusy(SSI3_BASE)) {}
    		SSIDataPut(SSI3_BASE, convertedValue & 0xFF);
    		while (SSIBusy(SSI3_BASE)) {}
    
    		GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, GPIO_PIN_2);
    
    	}
    
    }
    

    I would really appreciate some help.

    PS.: Sorry about the pictures, I didn't have a flash drive at the lab this time.

  • Geovani Alves said:
    I would really appreciate some help.

    Would not that be better stated as "some MORE help?"    

    Two or three here have responded to your need - your use of "some" is incorrect - even "Off-Putting" (you've already received "some help") - have you not?

    My advice - to "slow" the input sine wave - has established the fact that your code - in general - does work.

    Unknown (at the present) is, "How you can increase code efficiency" or (even if you can) so that your (newly) listed goal of 40KHz may be reached...

    Shouldn't it be your job to, "Work the math - upon a function by function basis - to see if what you seek, "is possible?"     Your helpers would appreciate (some) help too...

  • Geovani Alves said:
    So, I slowed down the frequency of the input sine wave, and around 1 kHz it worked fine, no distortion on the output.

    Good

    Geovani Alves said:
    The Chip Select seems fine.

    Well you need to 'scope it at the point of failure. Having said that, I beg to differ with your conclusions, especially given your stated goal of sampling a 40kHz sine wave.

    First all three of your scope plots show you are currently sampling at ~80kHz. That gives you the stepped sine response.

    However these chip selects show an issue. If you check those chip select on times, they add up to about 10uS out of a total period of 12uS or ~83%. Basically you are maxed out, not surprising consider you have no waits in your sampling.

    So your 'distortion' is simply your sampling steps. Your sampling artifacts are simply going to get worse as you increase the input frequency. Once you exceed 8 or 10kHz I expect some aliasing will creep in, you might even see a nice sine wave, or you could see the flat sections you showed in your first capture.

    You need to spend a little time optimizing your I/O. I suspect you will find large gaps between bytes (something you can measure) as a for instance since you don't make any use of the FIFO. You can speed this up, whether you can get you needed 5 to 10x increase in sampling rate, I don't know.

    Robert

  • Might the use of the MCU's ADC combined w/µDMA implementation of the SPI controlled/ordered DAC achieve (some) "speed-up" (and program/code efficiency?)

    Once more - such becomes a job (very much) down the "KISS" wheel-house. (i.e. systematically build a series of "reduced/individual solutions" - test/verify each - and only then attempt to "join or optimally combine" them.)
  • cb1_mobile said:
    Might the use of the MCU's ADC combined w/µDMA implementation of the SPI controlled/ordered DAC achieve (some) "speed-up" (and program/code efficiency?)

    I think so, I was hinting at the internal A/D the tag. I'm not sure uDMA can be used in this context but maybe off of a timer, or triggered explicitly after scaling the output. That might end up being more work that using it with an interrupt or polling. I don't think we know enough about the actual use to hazard an estimate. It's a possibility to consider though.

    cb1_mobile said:
    Once more - such becomes a job (very much) down the "KISS" wheel-house. (i.e. systematically build a series of "reduced/individual solutions" - test/verify each - and only then attempt to "join or optimally combine" them.)

    Yes, and it's not clear, to me at least, whether the goal can be reached. It's not an insubstantial throughput.

    Robert

  • Robert Adsett72 said:
    Yes, and it's not clear, to me at least, whether the goal can be reached. It's not an insubstantial throughput.

    Agreed - yet the throughput depends upon the execution times of "several functions" - and the "isolation" (naturally) provided by a properly designed, "KISS" approach - should glean such detail far faster than vendor's (seemingly) preferred, "All at once" approach.     (as they (always) resist the prescription of KISS - preferring endless - inconsistent/deviating instructions - (unmemorable) and none of the impact/recognition of the universal/heralded, "KISS!"