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.

MSP430F47186: Being SPI Slave

Other Parts Discussed in Thread: MSP430F47186

Hi,

 

There is one processor which has ARM core and it has to be an SPI Master. And there is MSP430F47186 on the same board which should act like an SPI slave and communicate with other processor.

Normally this communication works nice, but on MSP430 side I have SD16A interrupt coming every 1ms and it needs 100us to be completed. When I enable this interrupt, SPI communication starts losing some bytes in the stream.

As I read in MSP430 user manuel, it doesn't have any FIFO for SPI. What is the proper way to solve such as issues? I don't want to use nested interrupts and I don't want to make SPI clock speed slow down.

 

Thanks.

 

  • BP,

    Have you tried using DMA to move the SPI data temporarirly to/from a RAM buffer?

    This should allow you to transfer data by interleaving it with CPU activity.

    Regards,

    Priya

     

  • Hi Priya,

     

    Actually, I'm not sure the benefit of DMA for SPI Slave mode. Current SPI receiving interrupt routine is not a simple "just receive and put it to somewhere in RAM". It is little bit clever. Incoming data is frame based. I mean, in that frame there is synchronization character, size of frame and CRC value. At least, it has variable length, and length information comes with the frame itself. Because of these, I don't know how I can use DMA efficiently.

    Do you have any suggestion?

     

    Thank you for the reply.

    BP.

  • Hi Priya,

     

    I also would like to ask that, If I used DMA for SPI Slave operation, what would the pracital data transfer limit be? MCLK = 8Mhz.

    In user manuel, it is written DMA requires 4xMCLK for a single transfer. Lets say, I choosed SPI clock speed as 16Mhz at master side. So each byte will be trasfered to MSP at 2Mhz. (because of 8 bit) Can DMA really handle that speed while MCLK=8Mhz?

    I couldn't see any restriction which depends on MCLK for SPI slave speed in device specific datasheet. Can SPI slave clock be faster than MCLK?

    Thanks,

    BP.

     

  • Hi,

     

    I enabled DMA for SPI. It seems I need two DMA channels, one is for receiving and other for sending. In our SPI protocol, I made some changes like canceling variable frame size. Now each time, MSP send and receives 128 bytes, frame size is constant.

    I enabled also DMA2 interrupt to trigger packet completed.

    MSP is a slave on SPI bus, and master SPI clock speed is 2.66Mhz. MSP MCLK is 8Mhz. It seems working but I wonder whether theoretically we are safe.

     According to user manual, the datasheet says, DMA requires 4xMCLK for one operation. Now I have 2 DMA operations, which means it needs 8xMCLK to complete one SPI transfer. But how is it working now?

    I have another question. Now DMA1 is assigned to SPI TX flag and DMA2 is assigned to SPI RX flag. DMA0 is also not empty, I’m using it inside SD16A interrupt for circular buffer. It shifts 64 word by one at each SD16A interrupt which occurs every milliseconds. The datasheet says that DMA operations are not interruptable by other DMA channels. Does that mean we can lose some bytes during DMA0 operation?

    Thank you.

     

    static void InitializeDMAForSPI(void)

    {

          UCB0CTL1 = UCSWRST;

          UCB0CTL0 = UCSYNCSPI | UCCKPLSPI | UCMSBSPI;

         

          // MSP Slave SPI Pin Conf.

          P3DIR_bit.P3DIR_0 = 0;  // CS Input

          P3DIR_bit.P3DIR_1 = 0;  // SIMO Input

          P3DIR_bit.P3DIR_2 = 1;  // SOMI Output

          P3DIR_bit.P3DIR_3 = 0;  // MCLK Input

         

          // Master is STR

          P3SEL_bit.P3SEL_0 = 0;  // CS-not required

          P3SEL_bit.P3SEL_1 = 1;  // SIMO

          P3SEL_bit.P3SEL_2 = 1;  // SOMI

          P3SEL_bit.P3SEL_3 = 1;  // MCLK

         

          UCB0CTL1 &= ~UCSWRST;   // Initialize USART state machine

         

          IE2_bit.UCB0RXIE = 0;

          IE2_bit.UCB0TXIE = 0;

         

          // DMA1 for SPI Transmit Buffer

          DMACTL0_bit.DMA1TSEL0 = 1;   

          DMACTL0_bit.DMA1TSEL1 = 0;

          DMACTL0_bit.DMA1TSEL2 = 1;

          DMACTL0_bit.DMA1TSEL3 = 1;  // UCB0TXIFG triggered

         

          DMA1CTL = DMA1LEVEL | DMADT_0 | DMASRCINCR_0 | DMADSTINCR_3| DMASBDB; // Level triger, single, source unchanged, dest increment

          DMA1SAL = (uint16_t)&UCB0TXBUF; // Start block address

          DMA1DAL = (uint16_t)&SPI_TX_BUF.Stream[0]; // Destination block address

          DMA1SZ = sizeof(SPI_TX_BUF); // max length

          DMA1CTL |= DMA1EN; // Enable DMA1   

         

          // DMA2 for SPI Receive Buffer

          DMACTL0_bit.DMA2TSEL0 = 0;   

          DMACTL0_bit.DMA2TSEL1 = 0;

          DMACTL0_bit.DMA2TSEL2 = 1;

          DMACTL0_bit.DMA2TSEL3 = 1;  // UCB0RXIFG triggered

         

          DMA2CTL = DMA2LEVEL | DMADT_0 | DMASRCINCR_0 | DMADSTINCR_3| DMASBDB | DMA2IE; // Level triger, single, source unchanged, dest increment, interrupt enabled

          DMA2SAL = (uint16_t)&UCB0RXBUF; // Start block address

          DMA2DAL = (uint16_t)&SPI_RX_BUF.Stream[0]; // Destination block address

          DMA2SZ = sizeof(SPI_RX_BUF); // max length

          DMA2CTL |= DMA2EN; // Enable DMA2

     

          // once when we start receiving frame, other side will receive frame start character to be sure synchronization

          SPI_TX_BUF.Base.Header.FrameStart = SPI_FRAME_START;

          UCB0TXBUF = SPI_TX_BUF.Stream[0];

    }

  • Hi all,

    Don't forget that SPI rates are given as bit rates, but the DMA operations in this case are byte operations.  You automatically have an 8:1 advantage.

    Also consider that the DMA controller is fairly wise in its use of "sync" cycles, and only 2x MCLK cycles are required for the actual data move operation.  So in the case of an SPI bit clock that equals MCLK, you still get 4 MCLK cycles of CPU activity out of every 8 MCLK cycles.  The 4 cycles when the CPU is halted are used 2x for the Rx channel and 2x for the Tx channel.

    Basepointer, your SPI clock frequency is enough slower than MCLK that your third DMA channel (for ADC) can also run comfortably.  The DMA controller is keeping up just fine with all three channels.

    Jeff

  • Hi Jeff,

     

    You are right, I forgot  8 bit divider :-)

    DMA0 works in SD16A interrupt is not used with single transfer. I’m using it in block transfer mode to realize circular buffer and it shifts 64 word in an array at a time. So we can say it takes 64*2*MCLK = 128 MCLK. I saw that this circular buffer has to be paid to implement fast FIR filter. I think this will make a problem for SPI transfer, right?

     

     

    #define ADC_BUFFER_SIZE 64

    __interrupt void SD16A_Interrupt(void)

    {  

        // circular buffer for ADC inputs  

        DMA0CTL = DMADT_1 | DMASRCINCR_2 | DMADSTINCR_2; // Block, source dec, dest dec

        DMA0SAL = (uint16_t)&m_ADC.ch0[ADC_BUFFER_SIZE-2]; // Start block address

        DMA0DAL = (uint16_t)&m_ADC.ch0[ADC_BUFFER_SIZE-1]; // Destination block address

        DMA0SZ = ADC_BUFFER_SIZE-1; // Block size

        DMA0CTL |= DMA0EN; // Enable DMA0

        DMA0CTL |= DMA0REQ;

        ..

        .. 

        m_ADC.ch0[0] = SD16MEM0;

    }

     

  • Yes, you're absolutely right.  A block transfer will get you into trouble.

    I think it would be better not to use the DMA controller to move that block of data.  Just a small fast loop with the CPU doing the job the old fashioned way.  This will insure the SPI work can continue properly.  C library function memmove( ) should be fast enough for you.

    I like the sound of your application.  You have demanding ADC work including FIR, and you also need to be an SPI slave with a decent bit rate.  Good stuff!

    Jeff

    [BP and Priya - Yes, I edited the heck out of this post after I realized that I had misunderstood what BP was doing!  Sorry for any confusion.]

**Attention** This is a public forum