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.

MSP430F5438A: 请教:DMA+SPI通讯,DMA将内存地址增长设置为地址不变,但是程序运行异常。

Part Number: MSP430F5438A

额,我遇到的问题比较奇怪,我尽可能描述清楚问题。

我使用MSP430F5438a,以下使用单片机代替MSP430F5438a

单片机与DSP通过DMA+SPI进行通讯。单片机作为SPI通讯的主机。

1、由于每次通讯单片机都是接收数据,但是标准SPI通讯要求发送同时接收,因此单片机维持着两段内存,分别是send_buf和recv_buf。send_buf是发送端缓存,而recv_buf是接收端缓存。

2、由于单片机与DSP通讯的目的是用于从DSP接收数据,单片机发送数据仅仅是为了保证SPI真正实现双端通讯,DSP端根本不关心接收到的数据是什么,会直接丢掉。

3、我使用两路DMA来保证SPI通讯双端通讯。到目前为止,一切正常。

4、由于单片机RAM紧张,我希望压缩send_buf缓存尺寸。由于发送数据DSP根本“不敢兴趣”,因此我在使用DMA发送数据时,将DMA发送端内存地址设置为地址不变,即发送端每次发送的都是固定地址的数据。

按照我的理解,这样做应该是可行的。但是,程序在大多数情况下运行是正常的,但是偶然情况下(可能一天会出现1~2次)会修改我栈中的数据,从而导致其它程序运行异常。

恳请各位帮助,不胜感激。

  • 因此我在使用DMA发送数据时,将DMA发送端内存地址设置为地址不变,即发送端每次发送的都是固定地址的数据。

    能否给出相关代码?

        /*
         * Configure DMA channel 0
         * Use TxString as source
         * Increment source address after every transfer
         */
        DMA_setSrcAddress(DMA_CHANNEL_0,
            (uint32_t)(uintptr_t)&TxString,
            DMA_DIRECTION_INCREMENT);

    是可以选择 #define DMA_DIRECTION_UNCHANGED                                  (DMASRCINCR_0) 的

    按照我的理解,这样做应该是可行的。

    是的,我也是这样认为的

    但是偶然情况下(可能一天会出现1~2次)会修改我栈中的数据,从而导致其它程序运行异常。

    能否详细说明一下?

  • 非常感谢你的回复。

    /* 此时不关心发送数据,因此禁止发送数据内存地址自增 */
            __data16_write_addr((unsigned short)&DMA0SA, (unsigned long)SrcAddr);
            __data16_write_addr((unsigned short)&DMA0DA, (unsigned long)&UCB0TXBUF);
            DMA0SZ = Len;
            DMA0CTL = DMADT_1 + DMASRCINCR_0 + DMADSTBYTE + DMASRCBYTE + DMALEVEL;
            /* DMA接收 */
            __data16_write_addr((unsigned short)&DMA1SA, (unsigned long)&UCB0RXBUF);
            __data16_write_addr((unsigned short)&DMA1DA, (unsigned long)DstAddr);
            DMA1SZ = Len;
            DMA1CTL = DMADT_1 + DMADSTINCR_3 + DMADSTBYTE + DMASRCBYTE + DMALEVEL + DMAIE;
            break;
    
    /* 其中第5行 DMASRCINCR_0 即代表发送端内存地址保持不变 */

    栈中数据出错表现为:(类似现象举例如下)

    void func(void)
    {
        bool flag = flase;
        
        if (flag)
        {
            /* 函数可以执行到这里,所以我严重怀疑栈数据出错!!! */
        }
    }

  • 建议您先参考下例程内的设置

    /* --COPYRIGHT--,BSD_EX
     * Copyright (c) 2012, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     *******************************************************************************
     *
     *                       MSP430 CODE EXAMPLE DISCLAIMER
     *
     * MSP430 code examples are self-contained low-level programs that typically
     * demonstrate a single peripheral function or device feature in a highly
     * concise manner. For this the code may rely on the device's power-on default
     * register values and settings such as the clock configuration and care must
     * be taken when combining code from several examples to avoid potential side
     * effects. Also see www.ti.com/grace for a GUI- and www.ti.com/msp430ware
     * for an API functional library-approach to peripheral configuration.
     *
     * --/COPYRIGHT--*/
    //******************************************************************************
    //  MSP430F543xA Demo - SPI TX & RX using DMA0 & DMA1 Single Transfer in Fixed
    //                     Address Mode
    //
    //  Description: This code has to be used with MSP430F543xA_uscia0_spi_10.c as
    //  slave SPI. DMA0 is used to transfer a single byte while DMA1 is used to
    //  RX from slave SPI at the same time. This code will set P1.0 if RX character
    //  is correct and clears P1.0 if received character is wrong. Watchdog in
    //  interval mode triggers block transfer every 1000ms.
    //  ACLK = REFO = 32kHz, MCLK = SMCLK = default DCO 1048576Hz
    //
    //                 MSP430F5438A
    //             -----------------
    //         /|\|              XIN|-
    //          | |                 | 32768Hz
    //          --|RST          XOUT|-
    //            |                 |
    //            |             P1.0|-> LED
    //            |                 |
    //            |             P3.4|-> Data Out (UCA0SIMO)
    //            |                 |
    //            |             P3.5|<- Data In (UCA0SOMI)
    //            |                 |
    //            |             P3.0|-> Serial Clock Out (UCA0CLK)
    //
    //  M. Morales
    //  Texas Instruments Inc.
    //  June 2009
    //  Built with CCE v3.1 Build 3.2.3.6.4 & IAR Embedded Workbench Version: 4.11B
    //******************************************************************************
    
    #include <msp430.h>
    #include <stdint.h>
    
    char TxString;
    char RxString;
    
    int main(void)
    {
      WDTCTL = WDT_ADLY_1000;                   // WDT 1000ms, ACLK, interval timer
      SFRIE1 |= WDTIE;                          // Enable WDT interrupt
      P1OUT &= ~0x01;                           // Clear P1.0
      P1DIR |= 0x01;                            // P1.0 = Output
      P3SEL |= 0x31;                            // P3.0,4,5 = USCI_A0 SPI Option
    
      UCA0CTL1 |= UCSWRST;                      // **Put state machine in reset**
      UCA0CTL0 = UCMST+UCSYNC+UCCKPL+UCMSB;     // 3-pin, 8-bit SPI master
                                                // Clock polarity high, MSB
      UCA0CTL1 = UCSSEL_2;                      // SMCLK
      UCA0BR0 = 0x02;                           // /2
      UCA0BR1 = 0x00;                           //
      UCA0MCTL = 0x00;                          // No modulation
      UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
    
      DMACTL0 = DMA1TSEL_16+DMA0TSEL_17;        // DMA0 - UCA0TXIFG
                                                // DMA1 - UCA0RXIFG
      // Setup DMA0
      __data20_write_long((uintptr_t) &DMA0SA,(uintptr_t) &TxString);
                                                // Source block address
      __data20_write_long((uintptr_t) &DMA0DA,(uintptr_t) &UCA0TXBUF);
                                                // Destination single address
      DMA0SZ = 1;                               // Block size
      DMA0CTL = DMASRCINCR_3+DMASBDB+DMALEVEL;  // inc src
    
      // Setup DMA1
      __data20_write_long((uintptr_t) &DMA1SA,(uintptr_t) &UCA0RXBUF);
                                                // Source block address
      __data20_write_long((uintptr_t) &DMA1DA,(uintptr_t) &RxString);
                                                // Destination single address
      DMA1SZ = 1;                               // Block size
      DMA1CTL = DMADSTINCR_3+DMASBDB+DMALEVEL;  // inc dst
    
      TxString = RxString = 0;                  // Clear TxString
                                                // Clear RxString
      __bis_SR_register(LPM3_bits + GIE);       // Enter LPM3 w/ interrupts
      __no_operation();                         // Required only for debugger
    }
    
    //------------------------------------------------------------------------------
    // Trigger DMA0 & DMA1 block transfer.
    //------------------------------------------------------------------------------
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=WDT_VECTOR
    __interrupt void WDT_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(WDT_VECTOR))) WDT_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
      if(TxString-1 == RxString)
        P1OUT |= 0x01;                          // Set P1.0 if True
      else
        P1OUT &= ~0x01;                         // Clear P1.0 if False
    
      TxString++;                               // Increment TxString counter
      DMA1CTL |= DMAEN;                         // DMA1 Enable
      DMA0CTL |= DMAEN;                         // DMA0 Enable
    }
    

    在msp430f5348a.h内使用的是

    SFR_20BIT(DMA0SA);                            /* DMA Channel 0 Source Address */ 

    所以在此使用的是 __data20_write_long

  • 感谢你的回复。

    你说的非常有道理,是应该使用20-bit地址长度的,我已改正。

    但我查看内存map,我所使用的变量未超过16-bit,即我的问题应该与20-bit地址长度无关。我还需要继续查找原因。

    还是非常感谢你。

  • 好的,期待您的反馈

  • 是我的代码出现问题了,与DMA和SPI无关。

    望知晓,麻烦各位了。

    感谢!