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.

MSP430FR5994: DMA中断

Part Number: MSP430FR5994
Other Parts Discussed in Thread: MSP-EXP430FR5994

使用DMA通道0和1,设置中断使能,直接复制的官方例程中的DMA中断服务程序,应该是需要两个,DMA0的和DMA1的,官方例程只有一种,如何配置才能分别触发通道0和1的中断,进入中断服务程序,官方中断服务程序如下
//------------------------------------------------------------------------------
// DMA Interrupt Service Routine
//------------------------------------------------------------------------------
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=DMA_VECTOR
__interrupt void DMA_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(DMA_VECTOR))) DMA_ISR (void)
#else
#error Compiler not supported!
#endif
{
switch(__even_in_range(DMAIV,16))
{
case 0: break;
case 2: // DMA0IFG = DMA Channel 0
P1OUT ^= BIT0; // Toggle P1.0 - PLACE BREAKPOINT HERE AND CHECK DMA_DST VARIABLE
break;
case 4: break; // DMA1IFG = DMA Channel 1
case 6: break; // DMA2IFG = DMA Channel 2
case 8: break; // DMA3IFG = DMA Channel 3
case 10: break; // DMA4IFG = DMA Channel 4
case 12: break; // DMA5IFG = DMA Channel 5
case 14: break; // DMA6IFG = DMA Channel 6
case 16: break; // DMA7IFG = DMA Channel 7
default: break;
}
}

  • 这里只编辑了通道0的ISR,编辑一下通道1的ISR,同时打开通道1的中断。

  • 编辑通道1的ISR应该如何做?

  • 仿照case2来编辑case4即可。

  • 参照case2编辑了case4,只能进入case2的中断服务函数,case4的始终无法进入,会一直在没有设置中断服务函数,空运行状态?我想是不是这个ISR的函数问题,这个案例是从5929的DMA案例中复制的,5994没有关于DMA的中断案例,所以5994的中断案例在哪里找?academy里面没有5994的DMA中断案例

  • 设置case4就会进入这里

  • 你看一下通道2的中断标志位有没有置位?如果置位了,没有进入ISR,那么应该是入口配置的问题。

  • 能不能提供一个430同时使用了两个DMA中断的案例

  • 这里中断函数的入口应该是没问题的,你这里中断标志也置位了。尝试下将case2注释掉看看能不能进入case4

  • 这种我试过,只是用DMA1通道,能正常进入case4

  • ISR应该就是这么写没错,应该有其他的原因导致没能进入case4. 能否用单步调试看看在通道1的FLAG置位后是否进入了ISR?

  • 我之前单步调试,DMA1传输完成之后中断标志置位,DNAIV也是0x0004,就是不进入case4,一直跳到上面的图片里面的TI_ISR_TRIP

  • 你更改之后的isr是什么?我这边调试下看看

  • #include <msp430.h>
    #include <stdio.h>
    #include <stdint.h>
    volatile unsigned int buf[512];
    volatile int input[256];
    //volatile unsigned int adc_result[512];

    unsigned char ADC12_flag=0;
    unsigned char DMA0flag=2;
    unsigned char DMA1flag=0;

    void GPIO_INIT(){

    // Configure GPIOs to it's lowest power state
    P1OUT = 0; // All P1.x reset
    P1DIR = 0xFF; // All P1.x outputs
    P2OUT = 0; // All P2.x reset
    P2DIR = 0xFF; // All P2.x outputs
    P3OUT = 0; // All P3.x reset
    P3DIR = 0xFF; // All P3.x outputs
    P4OUT = 0; // All P4.x reset
    P4DIR = 0xFF; // All P4.x outputs
    P5OUT = 0; // All P5.x reset
    P5DIR = 0xFF; // All P5.x outputs
    P6OUT = 0; // All P6.x reset
    P6DIR = 0xFF; // All P6.x outputs
    P7OUT = 0; // All P7.x reset
    P7DIR = 0xFF; // All P7.x outputs
    P8OUT = 0; // All P8.x reset
    P8DIR = 0xFF; // All P8.x outputs
    PJOUT = 0; // All PJ.x reset
    PJDIR = 0xFFFF; // All PJ.x outputs

    P1SEL0 |= BIT3; // configure P1.3/A3 for ADC function
    P1SEL1 |= BIT3; //

    P3DIR |= BIT4;
    P3SEL1 |= BIT4; // Output MCLK
    P3SEL0 |= BIT4;

    // Disable the GPIO power-on default high-impedance mode to activate
    // previously configured port settings
    PM5CTL0 &= ~LOCKLPM5;

    }
    void CLOCK_init(){
    // Clock System Setup
    CSCTL0_H = CSKEY_H; // Unlock CS registers
    CSCTL1 = DCOFSEL_0; // Set DCO to 1MHz
    CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
    // Per Device Errata set divider to 4 before changing frequency to
    // prevent out of spec operation from overshoot transient
    CSCTL3 = DIVA__4 | DIVS__4 | DIVM__4; // Set all corresponding clk sources to divide by 4 for errata
    CSCTL1 = DCOFSEL_6; // Set DCO to 8MHz
    // Delay by ~10us to let DCO settle. 60 cycles = 20 cycles buffer + (10us / (1/4MHz))
    __delay_cycles(60);
    CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1; // Set all dividers
    CSCTL0_H = 0; // Lock CS Registers

    }
    void TIMER_init(){
    // Configure Timer0_A3 to periodically trigger the ADC12 设置定时器周期
    TA0CCR0 = 250; // PWM Period
    TA0CCTL1 = OUTMOD_7; // TACCR1 set/reset
    TA0CCR1 = 10; // TACCR1 PWM Duty Cycle
    TA0CTL = TASSEL__SMCLK | MC__UP | TACLR; // ACLK, up mode

    }
    void DMA_init(){
    // Configure DMA channel 0

    __data20_write_long((uintptr_t) &DMA0SA,(uintptr_t) &ADC12MEM0);
    // Source block address
    __data20_write_long((uintptr_t) &DMA0DA,(uintptr_t) &buf[0]);
    // Destination single address
    DMA0SZ =256; // Block size
    // DMA0CTL &= ~DMAIFG; //清楚中断标志,防止未发生中断前已置位
    DMA0CTL = DMADT_4 | DMASRCINCR_0 | DMADSTINCR_3 | DMAIE; // Rpt, inc
    DMACTL0|= DMA0TSEL_26; //DMA触发源ADCIFG
    DMA0CTL|= DMAEN; // Enable DMA0

    /*Configure DMA channel 1*/
    __data20_write_long((uintptr_t) &DMA1SA,(uintptr_t) &buf[0]);
    __data20_write_long((uintptr_t) &DMA1DA,(uintptr_t) &input);
    DMA1SZ =256; // Block size
    // DMA1CTL &= ~DMAIFG; //清楚中断标志,防止未发生中断前已置位
    DMA1CTL = DMADT_5 | DMASRCINCR_3 | DMADSTINCR_3 | DMAIE ; // Rpt, inc

    DMA1CTL|= DMAEN; // Enable DMA0


    }
    void ADC12_init(){
    ADC12CTL0 = ADC12SHT0_0 | ADC12ON; // Sampling time, S&H=4(4个采样保持AD时钟周期), ADC12 on开启AD
    // Use TA0.1 to trigger, and repeated-single-channel 脉冲采样模式,触发源SAMPCON来自采样样本定时器,它的输入来自定时器TA0.1(数据手册) ,选择单通道重复转换模式,时钟源SMCLK
    ADC12CTL1 = ADC12SHP | ADC12SHS_1 | ADC12CONSEQ_2 | ADC12SSEL_3;
    // A1 ADC input select; Vref+ = AVCC 中断源选择,选择A1通道,序列未结束,参考电压默认没有设置
    ADC12MCTL0 = ADC12INCH_3 | ADC12EOS;
    ADC12CTL2 |= ADC12RES_2; //转换的位数12
    // ADC12IER0 |= ADC12IE0; // Enable ADC interrupt 使能ADC12IFGO中断
    ADC12IER2 |= ADC12TOVIE; //使能ADC转换时间溢出中断
    ADC12IER2 |= ADC12OVIE; //使能MEM缓存存储器溢出中断位
    ADC12CTL0 |= ADC12ENC ; // Start sampling/conversion 开启AD转换
    __bis_SR_register(GIE); // Enter LPM0, enable interrupts
    }
    int main(void)
    {
    WDTCTL = WDTPW | WDTHOLD; // Stop WDT

    GPIO_INIT();
    CLOCK_init();
    TIMER_init();
    DMA_init();
    // __bis_SR_register(GIE); // 打开全局中断
    /*
    while(1){
    P1OUT|= 0x01; // P1.0 = 1, LED on
    DMA0CTL|= DMAREQ; // Trigger block transfer

    }
    */
    P1OUT |= BIT1; // P1.1 = 1
    ADC12_init();
    while(1){
    switch(DMA0flag){
    case 0:
    DMA1CTL|= DMAREQ; // 软件触发DMA1转移数据
    DMA0flag=2;
    break;
    case 1:
    DMA1CTL|= DMAREQ; // 软件触发DMA1转移数据
    DMA0flag=2;
    break;
    default :
    break;
    }
    }


    __no_operation();

    return 0;
    }

    //------------------------------------------------------------------------------
    // DMA Interrupt Service Routine
    //------------------------------------------------------------------------------
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=DMA_VECTOR
    __interrupt void DMA_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(DMA_VECTOR))) DMA_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
    switch(__even_in_range(DMAIV,16))
    {
    case 0: break;
    case 2: // DMA0IFG = DMA Channel 0
    switch(ADC12_flag){
    case 0:
    DMA0flag=0;
    DMA0CTL&= ~DMAEN; // Enable DMA0
    __data20_write_long((uintptr_t) &DMA0DA,(uintptr_t) &buf[256]);
    DMA0CTL|= DMAEN; // Enable DMA0
    ADC12_flag=1;
    break;
    case 1:
    DMA0flag=1;
    DMA0CTL&= ~DMAEN; // Enable DMA0
    __data20_write_long((uintptr_t) &DMA0DA,(uintptr_t) &buf[0]);
    DMA0CTL|= DMAEN; // Enable DMA0
    ADC12_flag=0;
    break;
    default :
    break;
    }

    break;
    case 4:
    DMA1flag=1;

    break; // DMA1IFG = DMA Channel 1

    /*
    case 6: break; // DMA2IFG = DMA Channel 2
    case 8: break; // DMA3IFG = DMA Channel 3
    case 10: break; // DMA4IFG = DMA Channel 4
    case 12: break; // DMA5IFG = DMA Channel 5
    case 14: break; // DMA6IFG = DMA Channel 6
    case 16: break; // DMA7IFG = DMA Channel 7
    default: break;*/
    }
    }

  • switch(__even_in_range(DMAIV,16))
    {
    case 0: break;
    case 2: // DMA0IFG = DMA Channel 0
    switch(ADC12_flag){
    case 0:
    DMA0flag=0;
    DMA0CTL&= ~DMAEN; // Enable DMA0
    __data20_write_long((uintptr_t) &DMA0DA,(uintptr_t) &buf[256]);
    DMA0CTL|= DMAEN; // Enable DMA0
    ADC12_flag=1;
    break;
    case 1:
    DMA0flag=1;
    DMA0CTL&= ~DMAEN; // Enable DMA0
    __data20_write_long((uintptr_t) &DMA0DA,(uintptr_t) &buf[0]);
    DMA0CTL|= DMAEN; // Enable DMA0
    ADC12_flag=0;
    break;
    default :
    break;
    }

    这里有两个case0。case1在这里是不起作用的,这case后面只能是偶数。

  • 你的意思是中断服务函数里面switch语句里面不能这样在用switxh语句是吗

  • switch在这里不能嵌套使用对吗?

  • /*
    *
    *
    * ADC每采样转换不会进入中断,采样一次就通过DMA传输一次至指定缓存,DMA为ADCMEM寄存器中断标志触发,采用重复单地址传输模式,传完256个点后DMA的使能位会自动置1,同时触发中断标志DMAIFG,解决循环传数问题
    *当通道0传输完成之后,通过DMA通道1将数据搬移至FFT运算的地址空间,此程序测试使用两个DMA通道能否触发各自中断
    */
    #include <msp430.h>
    #include <stdio.h>
    #include <stdint.h>
    volatile unsigned int buf[512];
    volatile int input[256];
    //volatile unsigned int adc_result[512];

    unsigned char flag=0;
    unsigned char DMA0flag=0;
    unsigned char DMA1flag=0;

    void GPIO_INIT(){

    // Configure GPIOs to it's lowest power state
    P1OUT = 0; // All P1.x reset
    P1DIR = 0xFF; // All P1.x outputs
    P2OUT = 0; // All P2.x reset
    P2DIR = 0xFF; // All P2.x outputs
    P3OUT = 0; // All P3.x reset
    P3DIR = 0xFF; // All P3.x outputs
    P4OUT = 0; // All P4.x reset
    P4DIR = 0xFF; // All P4.x outputs
    P5OUT = 0; // All P5.x reset
    P5DIR = 0xFF; // All P5.x outputs
    P6OUT = 0; // All P6.x reset
    P6DIR = 0xFF; // All P6.x outputs
    P7OUT = 0; // All P7.x reset
    P7DIR = 0xFF; // All P7.x outputs
    P8OUT = 0; // All P8.x reset
    P8DIR = 0xFF; // All P8.x outputs
    PJOUT = 0; // All PJ.x reset
    PJDIR = 0xFFFF; // All PJ.x outputs

    P1SEL0 |= BIT3; // configure P1.3/A3 for ADC function
    P1SEL1 |= BIT3; //

    P3DIR |= BIT4;
    P3SEL1 |= BIT4; // Output MCLK
    P3SEL0 |= BIT4;

    // Disable the GPIO power-on default high-impedance mode to activate
    // previously configured port settings
    PM5CTL0 &= ~LOCKLPM5;

    }
    void CLOCK_init(){
    // Clock System Setup
    CSCTL0_H = CSKEY_H; // Unlock CS registers
    CSCTL1 = DCOFSEL_0; // Set DCO to 1MHz
    CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
    // Per Device Errata set divider to 4 before changing frequency to
    // prevent out of spec operation from overshoot transient
    CSCTL3 = DIVA__4 | DIVS__4 | DIVM__4; // Set all corresponding clk sources to divide by 4 for errata
    CSCTL1 = DCOFSEL_6; // Set DCO to 8MHz
    // Delay by ~10us to let DCO settle. 60 cycles = 20 cycles buffer + (10us / (1/4MHz))
    __delay_cycles(60);
    CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1; // Set all dividers
    CSCTL0_H = 0; // Lock CS Registers

    }
    void TIMER_init(){
    // Configure Timer0_A3 to periodically trigger the ADC12 设置定时器周期
    TA0CCR0 = 250; // PWM Period
    TA0CCTL1 = OUTMOD_7; // TACCR1 set/reset
    TA0CCR1 = 10; // TACCR1 PWM Duty Cycle
    TA0CTL = TASSEL__SMCLK | MC__UP | TACLR; // ACLK, up mode

    }
    void DMA_init(){
    // Configure DMA channel 0

    __data20_write_long((uintptr_t) &DMA0SA,(uintptr_t) &ADC12MEM0);
    // Source block address
    __data20_write_long((uintptr_t) &DMA0DA,(uintptr_t) &buf[0]);
    // Destination single address
    DMA0SZ =256; // Block size
    // DMA0CTL &= ~DMAIFG; //清楚中断标志,防止未发生中断前已置位
    DMA0CTL = DMADT_4 | DMASRCINCR_0 | DMADSTINCR_3 | DMAIE; // Rpt, inc
    DMACTL0|= DMA0TSEL_26; //DMA触发源ADCIFG
    DMA0CTL|= DMAEN; // Enable DMA0

    /*Configure DMA channel 1*/

    __data20_write_long((uintptr_t) &DMA1DA,(uintptr_t) &input);
    DMA1SZ =256; // Block size
    // DMA1CTL &= ~DMAIFG; //清楚中断标志,防止未发生中断前已置位
    DMA1CTL = DMADT_5 | DMASRCINCR_3 | DMADSTINCR_3 | DMAIE ; // Rpt, inc

    }
    void ADC12_init(){
    ADC12CTL0 = ADC12SHT0_0 | ADC12ON; // Sampling time, S&H=4(4个采样保持AD时钟周期), ADC12 on开启AD
    // Use TA0.1 to trigger, and repeated-single-channel 脉冲采样模式,触发源SAMPCON来自采样样本定时器,它的输入来自定时器TA0.1(数据手册) ,选择单通道重复转换模式,时钟源SMCLK
    ADC12CTL1 = ADC12SHP | ADC12SHS_1 | ADC12CONSEQ_2 | ADC12SSEL_3;
    // A1 ADC input select; Vref+ = AVCC 中断源选择,选择A1通道,序列未结束,参考电压默认没有设置
    ADC12MCTL0 = ADC12INCH_3 | ADC12EOS;
    ADC12CTL2 |= ADC12RES_2; //转换的位数12
    // ADC12IER0 |= ADC12IE0; // Enable ADC interrupt 使能ADC12IFGO中断
    ADC12IER2 |= ADC12TOVIE; //使能ADC转换时间溢出中断
    ADC12IER2 |= ADC12OVIE; //使能MEM缓存存储器溢出中断位
    ADC12CTL0 |= ADC12ENC ; // Start sampling/conversion 开启AD转换
    __bis_SR_register(GIE); // Enter LPM0, enable interrupts
    }
    int main(void)
    {
    WDTCTL = WDTPW | WDTHOLD; // Stop WDT

    GPIO_INIT();
    CLOCK_init();
    TIMER_init();
    DMA_init();
    // __bis_SR_register(GIE); // 打开全局中断
    /*
    while(1){
    P1OUT|= 0x01; // P1.0 = 1, LED on
    DMA0CTL|= DMAREQ; // Trigger block transfer

    }
    */
    P1OUT |= BIT1; // P1.1 = 1
    ADC12_init();
    while(1){
    if(DMA0flag==1){
    switch(flag){
    case 1:
    DMA1CTL&= ~DMAEN;
    __data20_write_long((uintptr_t) &DMA1SA,(uintptr_t) &buf[0]);
    DMA1CTL|= DMAEN; // Enable DMA0
    DMA1CTL|= DMAREQ; // 软件触发DMA1转移数据
    DMA0flag=0;
    break;
    case 0:
    DMA1CTL&= ~DMAEN;
    __data20_write_long((uintptr_t) &DMA1SA,(uintptr_t) &buf[256]);
    DMA1CTL|= DMAEN; // Enable DMA0
    DMA1CTL|= DMAREQ; // 软件触发DMA1转移数据
    DMA0flag=0;
    break;
    default :
    break;
    }
    }

    }


    __no_operation();

    return 0;
    }

    //------------------------------------------------------------------------------
    // DMA Interrupt Service Routine
    //------------------------------------------------------------------------------
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=DMA_VECTOR
    __interrupt void DMA_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(DMA_VECTOR))) DMA_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
    switch(__even_in_range(DMAIV,16))
    {
    case 0: break;
    case 2: // DMA0IFG = DMA Channel 0
    if(flag==0){
    DMA0CTL&= ~DMAEN;
    __data20_write_long((uintptr_t) &DMA0DA,(uintptr_t) &buf[256]);

    DMA0CTL|= DMAEN; // Enable DMA0
    DMA0flag=1;
    flag=1;
    }
    else{
    DMA0CTL&= ~DMAEN;
    __data20_write_long((uintptr_t) &DMA0DA,(uintptr_t) &buf[0]);

    DMA0CTL|= DMAEN; // Enable DMA0
    DMA0flag=1;
    flag=0;

    }

    break;
    case 4:
    DMA1flag=1;

    break; // DMA1IFG = DMA Channel 1

    /*
    case 6: break; // DMA2IFG = DMA Channel 2
    case 8: break; // DMA3IFG = DMA Channel 3
    case 10: break; // DMA4IFG = DMA Channel 4
    case 12: break; // DMA5IFG = DMA Channel 5
    case 14: break; // DMA6IFG = DMA Channel 6
    case 16: break; // DMA7IFG = DMA Channel 7
    default: break;*/
    }
    }

    我把中断服务函数里面嵌套使用的switch改了,还是会进入空循环

  • 我在我的板子上跑一下后回复您。

  • #include "msp430.h"
    #include <stdint.h>
    
    int main(void)
    {
      WDTCTL = WDTPW | WDTHOLD;                 // Stop WDT
    
      // Configure GPIO
      P1OUT = 0;
      P1DIR = BIT0;             // For LED
    
      P4OUT = 0;
      P4DIR = BIT6;
    
    
      // Disable the GPIO power-on default high-impedance mode to activate
      // previously configured port settings
      PM5CTL0 &= ~LOCKLPM5;
    
      // Configure DMA channel 0
      __data20_write_long((uintptr_t) &DMA0SA,(uintptr_t) 0x1C20);
                                                // Source block address
      __data20_write_long((uintptr_t) &DMA0DA,(uintptr_t) 0x1C40);
                                                // Destination single address
      DMA0SZ = 16;                              // Block size
      DMA0CTL = DMADT_5 | DMASRCINCR_3 | DMADSTINCR_3; // Rpt, inc
      DMA0CTL |= DMAEN | DMAIE;                         // Enable DMA0
    
      __data20_write_long((uintptr_t) &DMA1SA,(uintptr_t) 0x1C98);
      __data20_write_long((uintptr_t) &DMA1DA,(uintptr_t) 0x1CB8);
    
      DMA1SZ = 16;                              // Block size
      DMA1CTL = DMADT_5 | DMASRCINCR_3 | DMADSTINCR_3; // Rpt, inc
      DMA1CTL |= DMAEN | DMAIE;
    
      __bis_SR_register(GIE);
      while(1)
      {
        //P1OUT |= 0x01;                          // P1.0 = 1, LED on
        DMA0CTL |= DMAREQ;                      // Trigger block transfer
        DMA1CTL |= DMAREQ;
        //P1OUT &= ~0x01;                         // P1.0 = 0, LED off
      }
    }
    
    
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=DMA_VECTOR
    __interrupt void DMA_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(DMA_VECTOR))) DMA_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
    switch(__even_in_range(DMAIV,16))
    {
        case 0: break;
        case 2: // DMA0IFG = DMA Channel 0
        P4OUT ^= BIT6; // Toggle P1.0 - PLACE BREAKPOINT HERE AND CHECK DMA_DST VARIABLE
        break;
        case 4: // DMA1IFG = DMA Channel 1
        P1OUT ^= BIT0;
        break;
        case 6: break; // DMA2IFG = DMA Channel 2
        case 8: break; // DMA3IFG = DMA Channel 3
        case 10: break; // DMA4IFG = DMA Channel 4
        case 12: break; // DMA5IFG = DMA Channel 5
        case 14: break; // DMA6IFG = DMA Channel 6
        case 16: break; // DMA7IFG = DMA Channel 7
        default: break;
    }
    }
    你好,由于我手边没有5994的板子,所以我用的是5969,这里是可以成功分别运行0和1通道的ISR。两个灯都可以闪烁,这两个型号的芯片使用的是同一个user guide,所以寄存器的配置基本相同。你可以修改下GPIO看看你这边LED能否闪烁。

  • 您好,因为我这边5994的开发板P4.6没有LED灯,所以我换成了P1.0和P1.1引脚,结果是P1.1灯正常切换,只能进入case2,始终无法进入case4。我使用的是TI的MSP-EXP430FR5994开发板。

  • 我单步调试中发现确实无法进入case4

  • DMAIV寄存器中的值也是0x002,对应DMA0通道中断

  • 有没有其他的板子能试一下?

  • 现在手上没有

  • 我推测是硬件问题,可能是板子坏了

  • 我找到问题了,为了讲清楚问题,请先让我概述一下设计内容,系统时钟MCLK、SMCLK、ACLK,全设置为8MHz,定时器TB0和ADC12都使用没有任何分频处理的SMCLK时钟,TB0的CCR0设置为250,CCR1设置为10,这样可以产生周期32kHz的占空比4百分之的PWM信号,此信号作为ADC12的采样转换的触发信号,脉冲触发,DMA0通道设置ADC12的转换完成标志作为触发信号,这样ADC12每采样转换一次,DMA0就转移一次ADC12MEM0里面的数据。之前一直跳入系统自带的空循环是因为我设置了ADC12的溢出中断ADC12TOVIE和ADC12OVIE,产生了ADC12OVIE中断,因为没有设置这个中断服务函数,所以一直进入系统空函数,这就是之前的问题。

    现在我有了一个新问题,为什么会产生这个ADC12OVIE中断?这个中断代表ADC12采样转换的数据存入ADC12MEM0寄存器,下一个转换数据存入之前,上一次的数据没有被读出,这里我不明白,TB031.25us产生一个上升沿脉冲,也就是ADC12也是这个时间间隔采样转换一次数据,DMA转移数据时间这么慢吗?不应该。我一步一步的调试,观察,第一种情况,把断电设置在DMA中断服务函数和ADC12中断服务函数那里,发现会一直产生ADC12OVIE中断,第二种情况,把断电设置在DMA0中断那里,切换地址都很正常,退出这个中断也正常,此时DMA0切换好了地址,按理说在往下步进,会重复被ADC12转换完成信号触发,可是还是和第一种情况一样,会进入ADC12OVIE中断,实在弄不懂是为什么

  • #include <msp430.h>
    #include <stdio.h>
    #include <stdint.h>
    volatile int buf[512];
    volatile int result[256];
    unsigned char bufflag=1;
    unsigned char DMA0flag=1;
    unsigned char DMA2flag=1;

    void GPIO_INIT(){

    /*Configure GPIOs to it's lowest power state*/
    P1OUT = 0;
    P1DIR = 0xFF;
    P2OUT = 0;
    P2DIR = 0xFF;
    P3OUT = 0;
    P3DIR = 0xFF;
    P4OUT = 0;
    P4DIR = 0xFF;
    P5OUT = 0;
    P5DIR = 0xFF;
    P6OUT = 0;
    P6DIR = 0xFF;
    P7OUT = 0;
    P7DIR = 0xFF;
    P8OUT = 0;
    P8DIR = 0xFF;
    PJOUT = 0;
    PJDIR = 0xFFFF;

    P1SEL0 |= BIT3; // 配置1.3引脚为AD输入通道
    P1SEL1 |= BIT3;

    /* Output SMCLK,观察时钟源变化*/
    P3DIR |= BIT4;
    P3SEL1 |= BIT4;
    P3SEL0 |= BIT4;

    /*定时器TB0.1输出测试,不需要测试时请屏蔽*/
    // P1SEL0 |= BIT4;
    /* Disable the GPIO power-on default high-impedance mode to activate previously configured port settings*/
    PM5CTL0 &= ~LOCKLPM5;
    }

    void CLOCK_init(){
    /*Clock System Setup*/
    CSCTL0_H = CSKEY_H; // Unlock CS registers
    CSCTL1 = DCOFSEL_0; // Set DCO to 1MHz
    CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
    // Per Device Errata set divider to 4 before changing frequency to
    // prevent out of spec operation from overshoot transient
    CSCTL3 = DIVA__4 | DIVS__4 | DIVM__4; // Set all corresponding clk sources to divide by 4 for errata
    CSCTL1 = DCOFSEL_6; // Set DCO to 8MHz
    // Delay by ~10us to let DCO settle. 60 cycles = 20 cycles buffer + (10us / (1/4MHz))
    __delay_cycles(60);
    CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1; // Set all dividers
    CSCTL0_H = 0; // Lock CS Registers
    }

    void TIMER_init(){
    /*使用定时器A1.1作为AD采样的触发信号,生成周期为32kHz,占空比为4%的PWM信号,该信号上升沿触发AD采样,配置如下*/
    TB0CCR0 = 250; /* PWM 周期*/
    TB0CCTL1 = OUTMOD_7; /* 定时器A的输出工作模式*/
    TB0CCR1 = 10; /* PWM高电平占空比*/
    TB0CTL = TASSEL__SMCLK | MC__UP | TACLR; /*定时器时钟源SMCLK,开启定时器*/

    }

    void ADC12_init(){
    ADC12CTL0 = ADC12SHT0_0 | ADC12ON; // Sampling time, S&H=4(4个采样保持AD时钟周期), ADC12 on开启AD
    // Use TB0.1 to trigger, and repeated-single-channel 脉冲采样模式,触发源SAMPCON来自采样样本定时器,它的输入来自定时器Tb0.1(数据手册) ,选择单通道重复转换模式,时钟源SMCLK
    ADC12CTL1 = ADC12SHP | ADC12SHS_3 | ADC12CONSEQ_2 | ADC12SSEL_3;
    // A1 ADC input select; Vref+ = AVCC 中断源选择,选择A3通道,序列未结束,参考电压默认没有设置
    ADC12MCTL0 = ADC12INCH_3 | ADC12EOS;
    ADC12CTL2 |= ADC12RES_2; //转换的位数12
    // ADC12IER0 |= ADC12IE0; // Enable ADC interrupt 使能ADC12IFGO中断
    ADC12IER2 |= ADC12TOVIE; //使能ADC转换时间溢出中断
    ADC12IER2 |= ADC12OVIE; //使能MEM缓存存储器溢出中断位
    ADC12CTL0 |= ADC12ENC ; // Start sampling/conversion 开启AD转换

    }

    int main(void)
    {
    WDTCTL = WDTPW | WDTHOLD; // Stop WDT


    GPIO_INIT();
    CLOCK_init();
    TIMER_init();


    ADC12_init();


    // Configure DMA channel 0
    __data20_write_long((uintptr_t) &DMA0SA,(uintptr_t) &ADC12MEM0);
    // Source block address
    __data20_write_long((uintptr_t) &DMA0DA,(uintptr_t) &buf[0]);
    // Destination single address
    DMA0SZ = 256; // Block size
    DMACTL0 |= DMA0TSEL_26;
    DMA0CTL = DMADT_4 | DMASRCINCR_3 | DMADSTINCR_3; // Rpt, inc
    DMA0CTL |= DMAEN | DMAIE; // Enable DMA0

    __data20_write_long((uintptr_t) &DMA1SA,(uintptr_t) &buf[0]);
    __data20_write_long((uintptr_t) &DMA1DA,(uintptr_t) &result);

    DMA1SZ = 256; // Block size
    DMA1CTL = DMADT_5 | DMASRCINCR_3 | DMADSTINCR_3; // Rpt, inc
    DMA1CTL |= DMAEN | DMAIE;

    __bis_SR_register(LPM0_bits + GIE); // LPM0, ADC12_ISR will force exit
    while(1)
    {
    if(DMA0flag==2){
    DMA1CTL |= DMAREQ;
    P1OUT |= 0x01; // P1.0 = 1, LED on
    DMA0flag=1;
    __no_operation();
    }

    }
    }


    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=DMA_VECTOR
    __interrupt void DMA_ISR(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(DMA_VECTOR))) DMA_ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
    switch(__even_in_range(DMAIV,16))
    {
    case 0: break;
    case 2: // DMA0IFG = DMA Channel 0
    DMA0CTL &= ~DMAEN;
    if(bufflag==1){
    __data20_write_long((uintptr_t) &DMA0DA,(uintptr_t) &buf[256]);
    DMA1CTL |= DMAEN | DMAIE;

    }
    else if(bufflag==2){
    __data20_write_long((uintptr_t) &DMA0DA,(uintptr_t) &buf[0]);
    DMA1CTL |= DMAEN | DMAIE;

    }
    DMA0flag=2;
    __bic_SR_register_on_exit(LPM0_bits); // Exit active CPU
    break;
    case 4: // DMA1IFG = DMA Channel 1
    P1OUT ^= BIT0;
    break;
    case 6: break; // DMA2IFG = DMA Channel 2
    case 8: break; // DMA3IFG = DMA Channel 3
    case 10: break; // DMA4IFG = DMA Channel 4
    case 12: break; // DMA5IFG = DMA Channel 5
    case 14: break; // DMA6IFG = DMA Channel 6
    case 16: break; // DMA7IFG = DMA Channel 7
    default: break;
    }
    }

    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=ADC12_B_VECTOR
    __interrupt void ADC12ISR (void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(ADC12_B_VECTOR))) ADC12ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
    switch(__even_in_range(ADC12IV, ADC12IV__ADC12RDYIFG))
    {
    case ADC12IV__NONE: break; // Vector 0: No interrupt
    case ADC12IV__ADC12OVIFG:
    __no_operation();
    break; // Vector 2: ADC12MEMx Overflow
    case ADC12IV__ADC12TOVIFG:
    __no_operation();
    break; // Vector 4: Conversion time overflow
    case ADC12IV__ADC12HIIFG: break; // Vector 6: ADC12BHI
    case ADC12IV__ADC12LOIFG: break; // Vector 8: ADC12BLO
    case ADC12IV__ADC12INIFG: break; // Vector 10: ADC12BIN
    case ADC12IV__ADC12IFG0: // Vector 12: ADC12MEM0 Interrupt


    break;
    case ADC12IV__ADC12IFG1: break; // Vector 14: ADC12MEM1
    case ADC12IV__ADC12IFG2: break; // Vector 16: ADC12MEM2
    case ADC12IV__ADC12IFG3: break; // Vector 18: ADC12MEM3
    case ADC12IV__ADC12IFG4: break; // Vector 20: ADC12MEM4
    case ADC12IV__ADC12IFG5: break; // Vector 22: ADC12MEM5
    case ADC12IV__ADC12IFG6: break; // Vector 24: ADC12MEM6
    case ADC12IV__ADC12IFG7: break; // Vector 26: ADC12MEM7
    case ADC12IV__ADC12IFG8: break; // Vector 28: ADC12MEM8
    case ADC12IV__ADC12IFG9: break; // Vector 30: ADC12MEM9
    case ADC12IV__ADC12IFG10: break; // Vector 32: ADC12MEM10
    case ADC12IV__ADC12IFG11: break; // Vector 34: ADC12MEM11
    case ADC12IV__ADC12IFG12: break; // Vector 36: ADC12MEM12
    case ADC12IV__ADC12IFG13: break; // Vector 38: ADC12MEM13
    case ADC12IV__ADC12IFG14: break; // Vector 40: ADC12MEM14
    case ADC12IV__ADC12IFG15: break; // Vector 42: ADC12MEM15
    case ADC12IV__ADC12IFG16: break; // Vector 44: ADC12MEM16
    case ADC12IV__ADC12IFG17: break; // Vector 46: ADC12MEM17
    case ADC12IV__ADC12IFG18: break; // Vector 48: ADC12MEM18
    case ADC12IV__ADC12IFG19: break; // Vector 50: ADC12MEM19
    case ADC12IV__ADC12IFG20: break; // Vector 52: ADC12MEM20
    case ADC12IV__ADC12IFG21: break; // Vector 54: ADC12MEM21
    case ADC12IV__ADC12IFG22: break; // Vector 56: ADC12MEM22
    case ADC12IV__ADC12IFG23: break; // Vector 58: ADC12MEM23
    case ADC12IV__ADC12IFG24: break; // Vector 60: ADC12MEM24
    case ADC12IV__ADC12IFG25: break; // Vector 62: ADC12MEM25
    case ADC12IV__ADC12IFG26: break; // Vector 64: ADC12MEM26
    case ADC12IV__ADC12IFG27: break; // Vector 66: ADC12MEM27
    case ADC12IV__ADC12IFG28: break; // Vector 68: ADC12MEM28
    case ADC12IV__ADC12IFG29: break; // Vector 70: ADC12MEM29
    case ADC12IV__ADC12IFG30: break; // Vector 72: ADC12MEM30
    case ADC12IV__ADC12IFG31: break; // Vector 74: ADC12MEM31
    case ADC12IV__ADC12RDYIFG: break; // Vector 76: ADC12RDY
    default: break;
    }
    }

  • 你好,昨晚的第一种情况一直进入ADC12OVIE的问题我解决了,现在我有个疑问?使用DMA0传输ADC12MEM0的数据,256个之后切换地址,在DMA的DMA0中断里面切换,这个时间会很长吗?切换之后退出中断,在运行软件触发DMA1转移刚才存满的内存时,会触发ADC12OVIE中断,难道使用DMA1的时候不能使用DMA0吗?

  • 这个时间会很长吗?

    这个不是很清楚,没有相关的数据。

    难道使用DMA1的时候不能使用DMA0吗?

    可以的。