Hi,
Here is a problem involving two TI products not playing nicely together...
The problem is explained in the last post here.
http://e2e.ti.com/support/data_converters/precision_data_converters/f/73/t/388126
This sounds like a software/firmware issue rather than chip. The chip (from the d/s, Timing Requirements on page 7) should be able to handle up to 20MHz clock for SCLK.
You may want to look at the configuration of the SSI; I would suspect that you may not be reading correctly at the slower speeds even though it may appear that is the case. If at 1.2MHz you don't read all the data, the slower will not read out all the data either.
So far my intuition tells me that there are certain SSI restrictions that are violated. I've followed the recommended protocol as outlined by TI Application Engineers so this problem seems to be a bit more complex. Maybe ssi.c needs to be examined in more detail?
My code:
#include <stdbool.h> #include <stdint.h> #include "inc/hw_memmap.h" #include "inc/hw_ints.h" #include "inc/hw_gpio.h" #include "inc/hw_nvic.h" #include "inc/hw_types.h" #include "driverlib/gpio.h" #include "driverlib/interrupt.h" #include "driverlib/pin_map.h" #include "driverlib/ssi.h" #include "driverlib/sysctl.h" #include "driverlib/systick.h" #include "driverlib/rom.h" #include "driverlib/rom_map.h" #include "driverlib/uart.h" #include "utils/uartstdio.h" #include "drivers/pinout.h" //#include "inc/tm4c1294ncpdt.h" //***************************************************************************** // //! //! This example uses the following peripherals and I/O signals on EK-TM4C1294XL. //! You must review these and change as needed for your own board: //! - SSI0 peripheral //! - GPIO Port A peripheral (for SSI0 pins) //! - SSI0CLK - PA2 //! - SSI0Tx - PA4 //! - SSI0Rx - PA5 //! //! - GPIO Port H peripheral (GPIO pin OUT) //! - CS - PH0 //! - RESET - PH1 //! //! - GPIO Port K peripheral (GPIO pin OUT) //! - START - PK6 //! //! - GPIO Port M peripheral (GPIO pin IN) //! - DRDY - PM6 //! //! For this example to work, the following connections are needed on the //! EK-TM4C1294XL evaluation board. //! - SSI0CLK(PA2) - CLK(3) //! - SSI0Tx(PA4) - DIN(11) //! - SSI0Rx(PA5) - DOUT(13) //! - CS(PH0) - CS(7) //! - RESET(PH1) - RESET(8) //! - START(PK6) - START(14) //! - DRDY(PM6) - DRDY(15) //! //! The following UART signals are configured only for displaying console //! messages for this example. These are not required for operation of SSI0. //! - UART0 peripheral //! - GPIO Port A peripheral (for UART0 pins) //! - UART0RX - PA0 //! - UART0TX - PA1 //! // //***************************************************************************** // uint32_t g_ui32SysClock; //Sent Data uint32_t opcode_tx[1]; uint32_t channel_code[8]; //Received Data uint32_t cfg_reg[21]; uint32_t rdata_rx[19]; uint32_t rx_stat[3]; uint32_t rx_data[8]; // //***************************************************************************** // // Configure the UART and its pins. This must be called before UARTprintf(). // //***************************************************************************** void ConfigureUART(void) { SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); GPIOPinConfigure(GPIO_PA0_U0RX); GPIOPinConfigure(GPIO_PA1_U0TX); GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1); UARTStdioConfig(0, 9600, g_ui32SysClock); } //***************************************************************************** // // This function sets up SPI0 to be used as Master in freescale mode. // //***************************************************************************** void InitSPI0(void) { SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); GPIOPinConfigure(GPIO_PA2_SSI0CLK); GPIOPinConfigure(GPIO_PA3_SSI0FSS); GPIOPinConfigure(GPIO_PA4_SSI0XDAT0); GPIOPinConfigure(GPIO_PA5_SSI0XDAT1); GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2); //ADS SPI settings are CPOL = 0 and CPHA = 1. SSIConfigSetExpClk(SSI0_BASE, g_ui32SysClock, SSI_FRF_MOTO_MODE_1, SSI_MODE_MASTER, 10000000, 8); SSIEnable(SSI0_BASE); } //***************************************************************************** // // Configure GPIO pins. This replaces the SSI0Fss with another pin. // //***************************************************************************** void InitGPIO(void) { // PH0 - CS // PH1 - RESET SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOH); GPIOPinTypeGPIOOutput(GPIO_PORTH_BASE, GPIO_PIN_0 | GPIO_PIN_1); GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_0, GPIO_PIN_0); GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_1, GPIO_PIN_1); // PK6 - START SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK); GPIOPinTypeGPIOOutput(GPIO_PORTK_BASE, GPIO_PIN_6); GPIOPinWrite(GPIO_PORTK_BASE, GPIO_PIN_6, 0); // PM6 - DRDY SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOM); GPIOPinTypeGPIOInput(GPIO_PORTM_BASE, GPIO_PIN_6); } //***************************************************************************** // // Write to SPI // //***************************************************************************** void spi_write(uint32_t len, uint32_t pui32DataTx[]) { uint32_t ui32Index; uint32_t pui32DataRx[19]; // // Read any residual data from the SSI port. This makes sure the receive // FIFOs are empty, so we don't read any unwanted junk. This is done here // because the SPI SSI mode is full-duplex, which allows you to send and // receive at the same time. The SSIDataGetNonBlocking function returns // "true" when data was returned, and "false" when no data was returned. // The "non-blocking" function checks if there is any data in the receive // FIFO and does not "hang" if there isn't. // while (SSIDataGetNonBlocking(SSI0_BASE, &pui32DataRx[0])) { } for (ui32Index = 0; ui32Index < len; ui32Index++) { // // Send the data using the "blocking" put function. This function // will wait until there is room in the send FIFO before returning. // This allows you to assure that all the data you send makes it into // the send FIFO. // SSIDataPut(SSI0_BASE, pui32DataTx[ui32Index]); } // // Wait until SSI0 is done transferring all the data in the transmit FIFO. // while (SSIBusy(SSI0_BASE)) { } } //***************************************************************************** // // Read from SPI // //***************************************************************************** void spi_read(uint32_t rx_len, uint32_t *rx_Data) { uint32_t ui32Index; uint32_t pui32DataRx[19]; // // Read any residual data from the SSI port. This makes sure the receive // FIFOs are empty, so we don't read any unwanted junk. This is done here // because the SPI SSI mode is full-duplex, which allows you to send and // receive at the same time. The SSIDataGetNonBlocking function returns // "true" when data was returned, and "false" when no data was returned. // The "non-blocking" function checks if there is any data in the receive // FIFO and does not "hang" if there isn't. // while(SSIDataGetNonBlocking(SSI0_BASE, &pui32DataRx[0])) { } // // Read bytes from RX FIFO. // for(ui32Index = 0; ui32Index < rx_len; ui32Index++) { // // Put dummy bytes out to read bytes in // SSIDataPut(SSI0_BASE, 0x00); // // Receive the data using the "blocking" Get function. This function // will wait until there is data in the receive FIFO before returning. // SSIDataGet(SSI0_BASE, &rx_Data[ui32Index]); // // Since we are using 8-bit data, mask off the MSB. // rx_Data[ui32Index] &= 0x00FF; } // // Wait until SSI0 is done transferring all the data in the transmit FIFO. // while(SSIBusy(SSI0_BASE)) { } } //***************************************************************************** // // Reads and parses the cell voltage registers // //***************************************************************************** void rdatac_parse(uint32_t rx_data[19], // Controls which cell voltage register is read back. uint32_t rx_output[8], // Array of the parsed cell codes uint32_t rx_status[3] ) { uint32_t parsed_cell; uint32_t data_counter = 3; //data counter uint32_t current_cell; //a.i for(current_cell = 0; current_cell<3; current_cell++) { rx_status[current_cell] = rx_data[current_cell]; } //a.ii for(current_cell = 0; current_cell<8; current_cell++) // This loop parses the read back data into cell voltages, it { // loops once for each of the 3 cell voltage codes in the register parsed_cell = rx_data[data_counter+1] + (rx_data[data_counter] << 8);//Each cell code is received as two bytes and is combined to // create the parsed cell voltage code rx_output[current_cell] = parsed_cell; data_counter = data_counter + 2; //Because cell voltage codes are two bytes the data counter //must increment by two for each parsed cell code } } //***************************************************************************** // // Read ADS Registers // //***************************************************************************** void ads_rreg(void){ //Read all Registers uint32_t rregOP[2]; rregOP[0] = 0x20; rregOP[1] = 0x14; GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_0, 0); //CS low spi_write(2,rregOP); spi_read(21, cfg_reg); GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_0, GPIO_PIN_0); //CS high } //***************************************************************************** // // Initialize // //***************************************************************************** void ads_init(void){ //Reset Pulse GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_1, 0); SysCtlDelay(10); //minimum pulse width timing specifications GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_1, GPIO_PIN_1); SysCtlDelay(400); //18 tclk cycles to complete initialization (9252ns ~ 10us) //Send SDATAC Command opcode_tx[0] = 0x11; GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_0, 0); //CS low spi_write(1, opcode_tx); GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_0, GPIO_PIN_0); //CS high } //***************************************************************************** // // Write ADS Config Registers // //***************************************************************************** void ads_config(uint32_t config1, uint32_t config2, uint32_t config3){ uint32_t refconfig1[3]; uint32_t refconfig2[3]; uint32_t refconfig3[3]; //Config1 refconfig1[0] = 0x41; refconfig1[1] = 0x00; refconfig1[2] = config1; //0x01 GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_0, 0); //CS low spi_write(3, refconfig1); GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_0, GPIO_PIN_0); //CS high //Config2 refconfig2[0] = 0x42; refconfig2[1] = 0x00; refconfig2[2] = config2; //0x60 GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_0, 0); //CS low spi_write(3, refconfig2); GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_0, GPIO_PIN_0); //CS high //Config3 refconfig3[0] = 0x43; refconfig3[1] = 0x00; refconfig3[2] = config3; //0xC0 GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_0, 0); //CS low spi_write(3, refconfig3); GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_0, GPIO_PIN_0); //CS high } //***************************************************************************** // // Write ADS Config Channels // //***************************************************************************** void ads_chnset(uint32_t channel_code[8]){ //Set Channel Settings uint32_t CHnSET[3]; CHnSET[0] = 0x45; CHnSET[1] = 0x00; CHnSET[2] = 0x10; uint32_t channel; for (channel = 0; channel <8; channel ++) { CHnSET[2] = channel_code[channel]; GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_0, 0); //CS low spi_write(3, CHnSET); GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_0, GPIO_PIN_0); //CS high CHnSET[0]++; } } //***************************************************************************** // // MAIN // //***************************************************************************** int main(void) { uint32_t read = 0; uint32_t i; g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000); ConfigureUART(); InitGPIO(); InitSPI0(); //Initialize ADS UARTprintf("\n\nInitialized. Starting ADS130E08.\n"); ads_init(); //Read Registers ads_rreg(); // UARTprintf("\nRREG:"); // for(i = 0; i < 21; i++){ // UARTprintf(" %x,", cfg_reg[i]); // } //Configure ADS ads_config(0x01,0x73,0xcc); //INTERNAL DC TEST - (0x01,0x73,0xcc) //INTERNAL PULSED TEST - (0x01,0x70,0xcc) //EXTERNAL MEASURE - (0x01,0x60,0xcc) //Set Channel Settings channel_code[0] = 0x10; channel_code[1] = 0x11; channel_code[2] = 0x11; channel_code[3] = 0x11; channel_code[4] = 0x11; channel_code[5] = 0x11; channel_code[6] = 0x11; channel_code[7] = 0x11; ads_chnset(channel_code); //Gain 1 - 0x10 //Shorted - 0x11 //TEST - 0x15 //Read Registers ads_rreg(); // UARTprintf("\nRREG:"); // for(i = 0; i < 21; i++){ // UARTprintf(" %x,", cfg_reg[i]); // } //START GPIOPinWrite(GPIO_PORTK_BASE, GPIO_PIN_6, GPIO_PIN_6); SysCtlDelay(400); //Wait // //Read Data Continuously // //RDATAC opcode_tx[0] = 0x10; GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_0, 0); //CS low spi_write(1, opcode_tx); GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_0, GPIO_PIN_0); //CS high // UARTprintf("\n\nRDATA CONTINUOUS"); GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_0, 0); //CS low // // uint32_t pui32DataRx2[19]; // while(SSIDataGetNonBlocking(SSI0_BASE, &pui32DataRx2[0])) // { // } // SSIConfigSetExpClk(SSI0_BASE, g_ui32SysClock, SSI_FRF_MOTO_MODE_1, // SSI_MODE_MASTER, 2000000, 8); // read = 1; while(1) { // UARTprintf("\n\nWaiting for DRDY high........"); while(GPIOPinRead(GPIO_PORTM_BASE, GPIO_PIN_6)){ //Wait for DRDY to be high read = 0; for(i=0;i<2;i++) read = 0; } // UARTprintf("Done."); // UARTprintf("\nWaiting..."); uint32_t pui32DataRx2[19]; while(SSIDataGetNonBlocking(SSI0_BASE, &pui32DataRx2[0])) { } do{ if (GPIOPinRead(GPIO_PORTM_BASE, GPIO_PIN_6) == 0){ spi_read(19, rdata_rx); read = 1; rdata_rx[0]=0; // UARTprintf("Read."); } else{ // UARTprintf("."); } }while(read == 0); // rdatac_parse(rdata_rx, rx_data, rx_stat); // UARTprintf("\nReceived :"); // for(i = 0; i < 8; i++){ // UARTprintf(" %i,", rx_data[i]); // } // // UARTprintf("\nSTATUS :"); // for(i = 0; i < 3; i++){ // UARTprintf(" %x,", rx_stat[i]); // } } GPIOPinWrite(GPIO_PORTH_BASE, GPIO_PIN_0, GPIO_PIN_0); //CS high // // Return no errors // return (0); }
Thanks,
Stephen