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.

TMS320F28388D: Problems communicating with SPI with an external ADC

Part Number: TMS320F28388D
Other Parts Discussed in Thread: ADS8686S, ADS8686SEVM-PDK, , SYSCONFIG, C2000WARE

Good morning, colleagues,

I am new to programming on Texas microcontrollers. I am programming a TMS320F28388D with its Docking Card. I want to communicate via SPI with a TI ADC, specifically the ADS8686S with its ADS8686SEVM-PDK evaluation board.
This ADC allows SPI communication via two channels SDOA for ADCA and SDOB for ADCB but I want to use only 1, so reading the datasheet, I ground SDOB and in SDOA the two conversions are sent.
My problem has to do with the SPI communication itself. I have made a code with which I basically want to perform some very basic functionalities:
1. First, write in the ADC registers to configure it the way I want (configuration, input voltage range, type of low pass filter, etc...).
2. Send it to convert a channel and have it give me back the conversion.

This ADC makes use of the SPI communication signals (PICO, POCI, SCLK, CS(GPIO output)), CONVST (GPIO output), BUSY (GPIO input) and they are used according to what is shown in the ADC datasheet timing diagram. I have made a code with the help of sysconfig (I am still very inexperienced) and it compiles the code. However, when I connect the two devices and connect the signals I see that it gets stuck in this loop.
I have checked with the oscilloscope that the SCLK output of the microcontroller is at 0, it does not generate clock pulses. I would like to know if you could help me with this code. Basically, reading the ADC datasheet I think it works as follows:

1. Write to ADC register:
- Set to 1 convst for a small period of 50ns.
- Subsequently, enable SPI communication by setting CS to 0. CLEAR
- The SPI frame is sent with the register to be configured.
- Wait to receive an interrupt FLAG for reception.
- Go to the interrupt routine to receive the message from the ADC and clear the flags.
- The CS is deactivated by setting 1.
2. Read ADC conversion:
- Set to 1 convst for a small period of 50ns.
- When set to 1 convst the ADC returns the Busy signal to 1 until the conversion is finished.

- When Busy returns to 0, i.e. when the conversion is finished, SPI communication is enabled by setting CS to 0. CLEAR
- Wait to receive a receive interrupt FLAG.
- Go to the interrupt routine to receive the ADC conversion and clear the flags.
- The CS is deactivated by setting it to 1. SET

I leave you the code I have done and the sysconfig, in case you can see why the clock signal is not even sent with the ADC, although in the debug it gets stuck in the while part of the interrupt flag.

#include "driverlib.h"
#include "device.h"
#include "board.h"
#include "f2838x_device.h"
//#include "C:/ti/c2000/C2000Ware_5_00_00_00/device_support/f2838x/headers/include/f2838x_device.h"
//#include "F28x_Project.h"

//#include "F2838x_PieCtrl.h"
//
//
//

#ifdef __cplusplus
#pragma DATA_SECTION("SpiaRegsFile")
#else
#pragma DATA_SECTION(SpiaRegs,"SpiaRegsFile");
#endif
volatile struct SPI_REGS SpiaRegs;

#ifdef __cplusplus
#pragma DATA_SECTION("GpioDataRegsFile")
#else
#pragma DATA_SECTION(GpioDataRegs,"GpioDataRegsFile");
#endif
volatile struct GPIO_DATA_REGS GpioDataRegs;



#ifdef __cplusplus
#pragma DATA_SECTION("PieVectTableFile")
#else
#pragma DATA_SECTION(PieVectTable,"PieVectTableFile");
#endif
volatile struct PIE_VECT_TABLE PieVectTable;

#ifdef __cplusplus
#pragma DATA_SECTION("DacaRegsFile")
#else
#pragma DATA_SECTION(DacaRegs,"DacaRegsFile");
#endif
volatile struct DAC_REGS DacaRegs;




volatile Uint16 lecturadatoADCdummy;
volatile Uint16 flag_conf_noconversion=1;
volatile Uint16 lecturaconvADCA;
volatile Uint16 lecturaconvADCB;

volatile Uint16 comandoADCconf;

Uint16 tramaConfADC=((1 << 15) | (0x2 << 9) | (0x0));     //MANDA TRAMA DE CONFIGURACIÓN DONDE SE DEJA A 0 MODO BURST, SEQEN, OSR, STATUSEN, CRCEN

Uint16 tramaRango_ADCA_0_3=((1 << 15) | (0x4 << 9) | (0x0)); //PONE EL RANGO DE ADC A DEL CANAL 0 AL 3 EN RANGO +-10V
Uint16 tramaRango_ADCA_4_7=((1 << 15) | (0x5 << 9) | (0x0)); //PONE EL RANGO DE ADC A DEL CANAL 4 AL 7 EN RANGO +-10V
Uint16 tramaRango_ADCB_0_3=((1 << 15) | (0x6 << 9) | (0x0)); //PONE EL RANGO DE ADC B DEL CANAL 0 AL 3 EN RANGO +-10V
Uint16 tramaRango_ADCB_4_7=((1 << 15) | (0x7 << 9) | (0x0)); //PONE EL RANGO DE ADC B DEL CANAL 4 AL 7 EN RANGO +-10V

Uint16 tramaFiltroPasoBajo=((1 << 15) | (0xD << 9) | (0x1)); //ESCRIBE FILTRO PASO BAJO DE FRECUENCIA DE CORTE 15kHz | ESCRIBIR 0x0 si se quiere de 39kHz o 0x2 si se quiere de 376kHz

Uint16 conv_ADCA_CH0=((1 << 15) | (0x3 << 9) | (0x0)); //TRAMA QUE ESCRIBE EN REGISTRO PARA ACTIVAR CONVERSIÓN DEL CANAL 0 en ADCA y ADCB. Si se quiere cambiar, ver mapa de registros

Uint16 conv_SEQ_STACK0=((1 << 15) | (0x20 << 9) | (0x0<<8) | (0x0)); //ESCRITURA DE STACK 0 CON SECUENCIA CHA0,CHB0 siguiendo al siguiente Stack
Uint16 conv_SEQ_STACK1=((1 << 15) | (0x21 << 9) | (0x0<<8) | (0x11)); //ESCRITURA DE STACK 1 CON SECUENCIA CHA1,CHB1 siguiendo al siguiente Stack
Uint16 conv_SEQ_STACK2=((1 << 15) | (0x22 << 9) | (0x0<<8) | (0x22)); //ESCRITURA DE STACK 2 CON SECUENCIA CHA2,CHB2 siguiendo al siguiente Stack
Uint16 conv_SEQ_STACK3=((1 << 15) | (0x23 << 9) | (0x0<<8) | (0x33)); //ESCRITURA DE STACK 3 CON SECUENCIA CHA3,CHB3 siguiendo al siguiente Stack
Uint16 conv_SEQ_STACK4=((1 << 15) | (0x24 << 9) | (0x0<<8) | (0x44)); //ESCRITURA DE STACK 4 CON SECUENCIA CHA4,CHB4 siguiendo al siguiente Stack
Uint16 conv_SEQ_STACK5=((1 << 15) | (0x25 << 9) | (0x0<<8) | (0x55)); //ESCRITURA DE STACK 5 CON SECUENCIA CHA5,CHB5 siguiendo al siguiente Stack
Uint16 conv_SEQ_STACK6=((1 << 15) | (0x26 << 9) | (0x0<<8) | (0x66)); //ESCRITURA DE STACK 6 CON SECUENCIA CHA6,CHB6 siguiendo al siguiente Stack
Uint16 conv_SEQ_STACK7=((1 << 15) | (0x26 << 9) | (0x1<<8) | (0x77)); //ESCRITURA DE STACK 7 CON SECUENCIA CHA7,CHB7 Volviendo al Stack 0 si burst mode. Si no, termina secuencia.


// SPI_receive16Bits(uint32_t base, SPI_endianess endianness, uint16_t dummyData, uint16_t txDelay);

// Main
//
volatile Uint16 DatoSPI;




interrupt void INT_SPIADC_EXT_CHAB_RX_ISR(void);
interrupt void INT_SPIADC_EXT_CHAB_TX_ISR(void);


void configuracionADC(void);
void lecturaconvADC(void);

void main(void)
{
    Uint16 comandoADC;


    //
    // Initialize device clock and peripherals
    //
    Device_init();

    //
    // Disable pin locks and enable internal pull ups.
    //
    Device_initGPIO();

    //
    // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    //
    Interrupt_initModule();

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    //
    Interrupt_initVectorTable();




    //
    // Disable sync(Freeze clock to PWM as well)
    //
    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);

    //
    // Configure GPIO0/1 , GPIO2/3 and GPIO4/5 as ePWM1A/1B, ePWM2A/2B and
    // ePWM3A/3B pins respectively
    // Configure EPWM Modules
    //


    Board_init();
    SPI_enableHighSpeedMode(SPIADC_EXT_CHAB_BASE);


    // Enable sync and clock to PWM
    //
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);

    //
    // Enable ePWM interrupts
    //


    //
    // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
    //
    EINT;
    ERTM;

    //
    // IDLE loop. Just sit and loop forever (optional):
    //

    PieVectTable.SPIA_RX_INT = &INT_SPIADC_EXT_CHAB_RX_ISR;
    PieVectTable.SPIA_TX_INT = &INT_SPIADC_EXT_CHAB_TX_ISR;
    /////////////////////////////////////////////REALIZAR CONFIGURACIÓN DEL ADC
    configuracionADC();
    ////////////

    //ESCRIBIR EN REGISTRO QUE SE QUIERE CONVERTIR CANAL 0 (TRAMA conv_ADCA_CH0) Y APLICAR SEÑAL DE CONVST


    lecturaconvADC();



    while(1){}


}

void configuracionADC(void){
   //ENVIAR CONFIGURACIÓN DE CONFIGURATION REGISTER 0x2

    GPIO_writePin(CONVST, 1);
     //Debe estar CONV high mínimo 50ns -VISTO EN OSCILOSCOPIO QUE HAY UN DELAY DE 480ns si se ponen seguidos los writepin de CONVST

  //  while (GPIO_readPin(BUSY)==1){} //Se espera a que se ponga a 0 BUSY

    GpioDataRegs.GPACLEAR.bit.GPIO23=1; //CS a 0 se activa.
    GPIO_writePin(CONVST, 0);
    comandoADCconf=tramaConfADC;
    SpiaRegs.SPITXBUF = comandoADCconf;            // Master transmite la configuración
    while(SpiaRegs.SPISTS.bit.INT_FLAG !=1) {} // Espera hasta que envíe todos los bits de la trama.
                                                //INTERRUPCIÓN DE RECEPCIÓN
    GpioDataRegs.GPASET.bit.GPIO23=1; //CS a 0 se desactiva.

    //ENVIAR CONFIGURACIÓN DE RANGO DE CANALES 0-3 DE ADCA

    GPIO_writePin(CONVST, 1);
    GpioDataRegs.GPACLEAR.bit.GPIO23=1; //CS a 0 se activa.
    GPIO_writePin(CONVST, 0);
    comandoADCconf=tramaRango_ADCA_0_3;
    SpiaRegs.SPITXBUF = comandoADCconf;            // Master transmite la configuración
    while(SpiaRegs.SPISTS.bit.INT_FLAG !=1) {} // Espera hasta que envíe todos los bits de la trama.
                                                        //INTERRUPCIÓN DE RECEPCIÓN
    GpioDataRegs.GPASET.bit.GPIO23=1; //CS a 0 se desactiva.

    //ENVIAR CONFIGURACIÓN DE RANGO DE CANALES 4-7 DE ADCA

        GPIO_writePin(CONVST, 1);
        GpioDataRegs.GPACLEAR.bit.GPIO23=1; //CS a 0 se activa.
        GPIO_writePin(CONVST, 0);
        comandoADCconf=tramaRango_ADCA_4_7;
        SpiaRegs.SPITXBUF = comandoADCconf;            // Master transmite la configuración
        while(SpiaRegs.SPISTS.bit.INT_FLAG !=1) {} // Espera hasta que envíe todos los bits de la trama.
                                                            //INTERRUPCIÓN DE RECEPCIÓN
        GpioDataRegs.GPASET.bit.GPIO23=1; //CS a 0 se desactiva.
    //ENVIAR CONFIGURACIÓN DE RANGO DE CANALES 0-3 DE ADCB

        GPIO_writePin(CONVST, 1);
        GpioDataRegs.GPACLEAR.bit.GPIO23=1; //CS a 0 se activa.
        GPIO_writePin(CONVST, 0);
        comandoADCconf=tramaRango_ADCB_0_3;
        SpiaRegs.SPITXBUF = comandoADCconf;            // Master transmite la configuración
        while(SpiaRegs.SPISTS.bit.INT_FLAG !=1) {} // Espera hasta que envíe todos los bits de la trama.
                                                                //INTERRUPCIÓN DE RECEPCIÓN
        GpioDataRegs.GPASET.bit.GPIO23=1; //CS a 0 se desactiva.

     //ENVIAR CONFIGURACIÓN DE RANGO DE CANALES 4-7 DE ADCA

        GPIO_writePin(CONVST, 1);
        GpioDataRegs.GPACLEAR.bit.GPIO23=1; //CS a 0 se activa.
        GPIO_writePin(CONVST, 0);
        comandoADCconf=tramaRango_ADCB_4_7;
        SpiaRegs.SPITXBUF = comandoADCconf;            // Master transmite la configuración
        while(SpiaRegs.SPISTS.bit.INT_FLAG !=1) {} // Espera hasta que envíe todos los bits de la trama.
                                                                        //INTERRUPCIÓN DE RECEPCIÓN
        GpioDataRegs.GPASET.bit.GPIO23=1; //CS a 0 se desactiva.


    //ENVIAR CONFIGURACIÓN DE FILTRO PASO BAJO DE ENTRADA
        GPIO_writePin(CONVST, 1);
        GpioDataRegs.GPACLEAR.bit.GPIO23=1; //CS a 0 se activa.
        GPIO_writePin(CONVST, 0);
        comandoADCconf=tramaFiltroPasoBajo;
        SpiaRegs.SPITXBUF = comandoADCconf;            // Master transmite la configuración
        while(SpiaRegs.SPISTS.bit.INT_FLAG !=1) {} // Espera hasta que envíe todos los bits de la trama.
                                                                                       //INTERRUPCIÓN DE RECEPCIÓN
        GpioDataRegs.GPASET.bit.GPIO23=1; //CS a 0 se desactiva.






         flag_conf_noconversion=0;




}


void lecturaconvADC(void){
    //ENVIAR CONFIGURACIÓN DE CONFIGURATION REGISTER 0x2

    GPIO_writePin(CONVST, 1); //uso de DEVICE_DELAY_US????
    GPIO_writePin(CONVST, 0);     //Debe estar CONV high mínimo 50ns -VISTO EN OSCILOSCOPIO QUE HAY UN DELAY DE 480ns si se ponen seguidos los writepin de CONVST
    while (GPIO_readPin(BUSY)==1){}

    GpioDataRegs.GPACLEAR.bit.GPIO23=1; //CS a 0 se activa.

    while(SpiaRegs.SPISTS.bit.INT_FLAG !=1) {} // Espera hasta que envíe todos los bits de la trama.
                                                    //INTERRUPCIÓN DE RECEPCIÓN
    GpioDataRegs.GPASET.bit.GPIO23=1; //CS a 0 se desactiva.
}


interrupt void INT_SPIADC_EXT_CHAB_RX_ISR(void){
    if (flag_conf_noconversion==1){
        SpiaRegs.SPIFFRX.bit.RXFFOVFCLR=1;  // Clear Overflow flag
        SpiaRegs.SPIFFTX.bit.TXFFINTCLR=1;  // Clear Interrupt flag
        SpiaRegs.SPIFFRX.bit.RXFFINTCLR=1;  // Clear Interrupt flag
       //  FlWaitADC_Ext=0;
        lecturadatoADCdummy = SpiaRegs.SPIRXBUF;     // Read data y resetea flag INT_FLAG

    }
    else{
        SpiaRegs.SPIFFRX.bit.RXFFOVFCLR=1;  // Clear Overflow flag
        SpiaRegs.SPIFFTX.bit.TXFFINTCLR=1;  // Clear Interrupt flag
        SpiaRegs.SPIFFRX.bit.RXFFINTCLR=1;  // Clear Interrupt flag
               //  FlWaitADC_Ext=0;
        lecturaconvADCA = SpiaRegs.SPIRXBUF;     // Read data y resetea flag INT_FLAG
   //     DAC_setShadowValue(, lecturaconvADCA);
    }



 //   PieCtrlRegs.PIEACK.all |= PIEACK_GROUP6;       // Issue PIE ack
}
interrupt void INT_SPIADC_EXT_CHAB_TX_ISR(void){
    SpiaRegs.SPIFFTX.bit.TXFFINTCLR = 1;  // Clear Interrupt flag
  //  PieCtrlRegs.PIEACK.all |= PIEACK_GROUP6;       // Issue PIE ACK
}

I also have doubts about the High-Speed mode and where I can configure that option in the sysconfig, according to the datasheet of the microcontroller, you can reach speeds of 50MHz but then I don't see that option in the sysconfig. What I do is to select the GPIO pins of PICO, POCI, SCLK of ata speed according to the datasheet of the microcontroller but nowhere the "SPICCR.HS_MODE = 1" is applied. If I choose a bitrate of 12.5MHz the program runs until the while loop while if I set it to 50MHz I get an error in SPI_Init().


So basically I would like to figure out the following things: if someone could help me to have a code that I can run on the board for this relatively simple functionality and why I get these errors and if someone could help me on how to implement the High-Speed mode whether it can be done from sysconfig or from sysconfig I would like to know how to implement the High-Speed mode.

I let you the zip with the sysconfig os the project too. I would be very grateful if you could help me. Sorry for maybe some dumb questions. Thank you in advance.

BR,

Pedro

PRUEBA_SPI_ADC_F28388D.zip

Serial 1-Wire data receive from ADC in SPI 

Serial register writting to ADC in SPI 

  • Hi Pedro,

    Glad to see that you're new to TI's C2000 MCUsSlight smile and no such thing as a dumb question! To preface, I am not familiar with ADS8686S or its evaluation board (you may want to try reaching out to that product line to garner further insight there if you haven't already), but I can certainly try to help clarify some items on the F2838x side. 

    A few initial questions so I can understand your goals better here:

    • Looks like F2838x is the controller and the ADS8686S will be the peripheral, is that correct (if it is correct, know that the SPICLK and chip select should be controlled by F2838x)?
    • Are you trying to use FIFO or non-FIFO mode?
    • Is there a particular reason you are needing to use high speed mode?
    • And when you step through your code, which "while" loop do you get stuck in (there are several so I want to know which one specifically)? If there is no SPICLK being output by the controller device, that explains why you are getting stuck in the "while" loop checking the buffer status. So first we need to get your SPICLK running.

    To help clarify the high speed mode: There are 2 items you need to do in order to use SPI high-speed mode:

    1. Be sure you set the HS_MODE bit to '1' to enable high speed mode (this bit is located in the SPICCR register)
      1. The max high speed is the LSPCLK/4, so for F2838x that would make 50MHz the max HS frequency
      2. Your confusion with this is quite valid as there is currently no designated way to set high speed mode within SysConfig at the moment (something we have noted and will work to incorporate in the future), but you can use a driverlib function or bitfield to set the HS_MODE (and you can still use SysConfig with this). 
    2. Make sure you are using the right GPIOs that support high speed mode capability (this is done in the GPIO module by using the GPxGMUX/GPxMUX registers).
      1. Refer to the F2838x datasheet section 6.5.5 High-Speed SPI Pin Muxing for the correct mux settings (e.g. you should use GPIO58, GPIO59, GPIO60, GPIO61 to use high speed mode on SPIA)

    Some other general guidance in the mean time:

    • A helpful tip (if you are new to SysConfig and didn't know already) is you can view the c code that is generate when you select settings by clicking on the arrows and opening "board.c":

    • There are also some other helpful videos/descriptions and links to resources found on C2000 Academy if you are able to spend some time exploring there.
    • Have you been able to look over some of the examples we have in C2000Ware? If not, you might find it very helpful to look over and try using some of the external loopback examples there to get familiar with the SPI module (located in the directory {C2000Ware}\driverlib\f2838x\examples\c28x\spi. 

    Best Regards,

    Allison

  • Good morning Allison,

    Thank you very much for your reply! I'm sorry to read it now but I was on christmas holidays. Regarding the initial questions you asked me:

    • Looks like F2838x is the controller and the ADS8686S will be the peripheral, is that correct (if it is correct, know that the SPICLK and chip select should be controlled by F2838x)? -> You are right, the F2838D is the controller SPI and the ADS8686S is the peripheral SPI
    • Are you trying to use FIFO or non-FIFO mode? -> Non-FIFO mode 
    • Is there a particular reason you are needing to use high speed mode?-> I would need the High-Speed mode because we want to take the data of the ADC as fast as possible. 
    • And when you step through your code, which "while" loop do you get stuck in (there are several so I want to know which one specifically)? If there is no SPICLK being output by the controller device, that explains why you are getting stuck in the "while" loop checking the buffer status. So first we need to get your SPICLK running -> The while loop I get stuck is the first one of all. In the function configuracionADC() in the first loop in line 184. What I want first is to run the SPICLK and then the data transfer but I don't know why even the SPICLK is not transmitted.

    Regarding what you said about High-Speed Mode, I set the HS_MODE bit to 1 and use the GPIO pins that are used for High-Speed, I did take this into account in the configuration. I find the tip to see the code generated in sysconfig very interesting. Regarding the C2000 Academy and the C200Ware examples, I did do them and I understood them. Thank you very much for your time Allison, I hope you can take a look at the answers to the questions you asked me.
    Have a nice day,

    Pedro

  • Hi Pedro,

    Thanks for the answers and information! Glad you were able to use the C2000 Academy and C2000Ware examples as well. 

    If you are trying to utilize high speed mode, you should only do so on the designated HS SPI capable pins. It looks like you are using GPIO23 as a manually controlled chip select pin from your code is there a reason you aren't using a default SPISTE pin and having it automatically toggle with communication? What are all of your external connections between the two devices (just as another item to double check)?

    Might be good to get in contact with the ADS8686 line since I'm not as familiar with the device's requirements, but looking into it a bit, the BUSY line should go high when CONVST is pulled high to start a conversion - are you seeing this happen even though you aren't seeing SPICLK? CS and SPICLK activity should come after these go high.

    Also, as noted in the TRM, there is no TX interrupt in non-FIFO mode but I see it designated in your code- are you considering using FIFO mode and implementing a TX interrupt?

    Best Regards,

    Allison

  • Hi Allison, 

    Thanks for your fast answer. No, there is not a reason why I chose a GPIO as a CS instead of the STE pin, maybe it's the best option isn't it, to reach the HS mode. Now I will have this issue pending because we are trying to communicate with a parallel bus with the ADC so it could reach more transmission speed.

    In case, we come back with the SPI solution I will tell you back. Thank you very much for your time, have a nice weekend.

    BR,

    Pedro

  • Hi Pedro,

    Thanks for the reply. Let me know if you are able to make any progress. Another suggestion would be to simplify the system by trying to test/debug your program with internal loopback mode enabled (which internally connects PICO to POCI) or by external loopback (using a wire to connect PICO and POCI (both without connections to the external peripheral device ADS8686) to see if you your setup is correct independent of the ADS8686 device. Once you have success looping back, you try communicating to the other device.

    Best Regards,

    Allison