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.

ADS1298 and MSP430F2618 DMA control

Other Parts Discussed in Thread: MSP430F2618, ADS1298

I use ADS1298 controlled by MSP430F2618 SPI interface to capture electrophysiology signal.
I send three 8-bit commands to ADS1298. Then the acquired results from ADS1298 are right.
But when I send one 24-bit command via MSP430F2618 DMA to ADS1298, it seems something
wrong. The first 24-bit data from ADS1298 is right, but the following results are wrong.
Here are some partial codes. If I don’t adopt interrupt command via DMA, how should I do or fix it?
Thanks very much.

-------------------------------------------------------------------------------
DMA initialize
-------------------------------------------------------------------------------

const unsigned char Sin_tab[] = { 0x00, 0x00, 0x00 };

void Init_DMA(void)
{
 DMACTL0 = DMA2TSEL_12 + DMA0TSEL_13;      // URXIFG1, MPY, UTXIFG1
 // DMACTL1 = ROUNDROBIN;
 DMA0SA = (unsigned int)&Sin_tab;                    // Source block address
 DMA0DA = (unsigned int)&UCB0TXBUF;                 // Destination
single address
 DMA0SZ = sizeof Sin_tab;                  // Block size
 DMA0CTL = DMALEVEL+ DMASRCINCR_3+DMADT_0 + DMASBDB +  DMAEN;  // Sng
rpt, config

// RX Store
 DMA2SA = (unsigned int)&UCB0RXBUF;        // Src address = UART RX Buffer
 DMA2DA = 0x240;            // Dst address = P1
 DMA2SZ = 27;                               // Size in bytes
 DMA2CTL = DMADT_0 +DMASBDB + DMADSTINCR_3+  DMAEN;     // Sng, config

}


-------------------------------------------------------------------------------------------------------------------------------------

How should I rewrite the following codes to get ADS1298 results via MSP430F2618 DMA ?
-------------------------------------------------------------------------------------------------------------------------------------

 

unsigned int spiSendByte(const unsigned int data)
{
  UCB0TXBUF = data;
  while((IFG2 & UCB0TXIFG)==0);
  while((IFG2 & UCB0RXIFG)==0);
  return(UCB0RXBUF);
}

int ADS1298ReadData(int fWaitForDataReady)
{

       if (comm1 == 0)              // open readly ads1298
       {

       ADS1298_init_Command(ADS1298_CMD_START);
       ADS1298_init_Command(ADS1298_CMD_RDATAC);

       P1OUT |=  ADS1298_START ;    //同步
       Delay_us(1);
       P1OUT &=  ~(ADS1298_START);
       comm1 = 1;                   //close readly ads1298

       }

       if (fWaitForDataReady)       //wait DRDR ready!
         ADS1298WaitForDataReady(0);

       for (char f = 0 ; f < 10 ; f++) // read A/D 16ch
        {

       switch(f)
       {
       case 0:
         {
           ADS1298AssertCS(1);
           spiSendByte(0);
           spiSendByte(0);
           spiSendByte(0);
           ADS1298AssertCS(0);
            break;
         }
        case 1:  //ch1
         {
           ADS1298AssertCS(1);
            while (!(UC1IFG&UCA1TXIFG));
           UCA1TXBUF = spiSendByte(0);
           while (!(UC1IFG&UCA1TXIFG));
           UCA1TXBUF = spiSendByte(0);
           while (!(UC1IFG&UCA1TXIFG));
           UCA1TXBUF = spiSendByte(0);


           ADS1298AssertCS(0);
           break;
         }
        case 2:  //ch2
         {
           ADS1298AssertCS(1);

            while (!(UC1IFG&UCA1TXIFG));
           UCA1TXBUF = spiSendByte(0);
           while (!(UC1IFG&UCA1TXIFG));
           UCA1TXBUF = spiSendByte(0);
           while (!(UC1IFG&UCA1TXIFG));
           UCA1TXBUF = spiSendByte(0);
           ADS1298AssertCS(0);
           break;
         }
        case 3:  //ch3...........................

  • your spiSendByte writes to TXBUF, then waits for TXBUF clear and RXBUF full. Due to the double-buffering, TXBUF usually is immediately clear. So the check is superfluous. And after a byte has been received, the byte you stored in TXBUF was definitely sent, as the transfers are synchronous.

    However, after asserting the slave CS, you immediately start sending the data, which might be too fast (see the slave specs).

    But you say it works, so fine. Apparently teh code execution times are long enough (rather coincidentally)

    About the DMA, well, you don't write your clock and USCI init code. If maxed-out, both triggers, TXIFG and RXIFG, are set almost simultaneously. It depends on the DMA priorities which one is served first. It may be that the wrong one is served first. Also, every transfer takes some MCLK cycles. If SPICLK == MCLK, you only have 8 clock cycles to do the transfer or you'll get a receive buffer overrun.
    remember: the first byte written to TXBUF is almos tinstantly forwarded to the output shift and a second byte is requested. That means that two 8 bit transfers are already in the works and will complete in 16 SPICLK cycles. So there are only 8 clock cycles to read the result of the first transfer before it is overwritten with the second byte. If the CPU is executing code when then happens,. it may be that even DMA is too slow to catch the data.
    Also, DMA is NOT triggered at all if the same trigger is set up for triggering an ISR. Either ISR or DMA.

  • my SPI_INIT

    void Init_SPI(void)
    {
      UCB0CTL0 |= UCMST+UCSYNC+UCMSB;           //3-pin, 8-bit SPI master
      UCB0CTL1 |= UCSSEL_2;                     // SMCLK
      UCB0BR0 = 0x02;                           // /2
      UCB0BR1 = 0;                              //
      UCB0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
    }

    my clock_init

    {
     
    if (CALBC1_16MHZ ==0xFF || CALDCO_16MHZ == 0xFF)                                    
      { 
        while(1);                               // If calibration constants erased
                                                // do not load, trap CPU!!
      } 
      BCSCTL1 = CALBC1_16MHZ;                    // Set DCO to 8MHz
      DCOCTL = CALDCO_16MHZ;
    }

  • Okay, let's see.

    In your current DMA setup, DMA0 always has highest priority (no round-robin). So you should use DMA0 for RX event. You're SPI master, so it doesn't matter whether you put something into TXBUF a cycle or two later. But if you read RXBUF too late, this will cause an overflow error and missing data. You should switch DMA0 and DMA2.

    then, you use UCBR0=2. This means your SPI is running with 1/2 of your MCLK speed. To ensure that it isn't a timing issue, you should go a few steps back and start with a slower clock. Remember, DMA is executing transfers when the trigger comes, while your program only does a read or write when it checks for a trigger. So the sequence of events may be completely different in DMA as it is in your software implementation.
    If everything is working, you can go back to full speed. And if things then no longer work, you can be sure that it is a timing problem :)

    Another thing is the trigger mode. I'm not sure whether this is a problem, but from the datasheet:
    "For proper operation, level-sensitive triggers can only be used when external trigger DMAE0 is selected as the trigger."

    Since the TX and RX flags are automatically reset when the proper action happens, you can set the triggers to edge sensitive.

     

     

**Attention** This is a public forum