Part Number:MSP430FR5994Other 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;
}
}
Ben Qin:
这里只编辑了通道0的ISR,编辑一下通道1的ISR,同时打开通道1的中断。
,
?? ?:
编辑通道1的ISR应该如何做?
,
Ben Qin:
仿照case2来编辑case4即可。
,
?? ?:
参照case2编辑了case4,只能进入case2的中断服务函数,case4的始终无法进入,会一直在没有设置中断服务函数,空运行状态?我想是不是这个ISR的函数问题,这个案例是从5929的DMA案例中复制的,5994没有关于DMA的中断案例,所以5994的中断案例在哪里找?academy里面没有5994的DMA中断案例
,
?? ?:
设置case4就会进入这里
,
Ben Qin:
你看一下通道2的中断标志位有没有置位?如果置位了,没有进入ISR,那么应该是入口配置的问题。
,
?? ?:
置位了
,
?? ?:
能不能提供一个430同时使用了两个DMA中断的案例
,
Ben Qin:
这里中断函数的入口应该是没问题的,你这里中断标志也置位了。尝试下将case2注释掉看看能不能进入case4
,
?? ?:
这种我试过,只是用DMA1通道,能正常进入case4
,
Ben Qin:
ISR应该就是这么写没错,应该有其他的原因导致没能进入case4. 能否用单步调试看看在通道1的FLAG置位后是否进入了ISR?
,
?? ?:
我之前单步调试,DMA1传输完成之后中断标志置位,DNAIV也是0x0004,就是不进入case4,一直跳到上面的图片里面的TI_ISR_TRIP
,
Ben Qin:
你更改之后的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;*/ }}
,
Ben Qin:
?? ? 说: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改了,还是会进入空循环
,
Ben Qin:
我在我的板子上跑一下后回复您。
,
Ben Qin:
#include "msp430.h" #include <stdint.h>int main(void) {WDTCTL = WDTPW | WDTHOLD;// Stop WDT// Configure GPIOP1OUT = 0;P1DIR = BIT0;// For LEDP4OUT = 0;P4DIR = BIT6;// Disable the GPIO power-on default high-impedance mode to activate// previously configured port settingsPM5CTL0 &= ~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 addressDMA0SZ = 16;// Block sizeDMA0CTL = DMADT_5 | DMASRCINCR_3 | DMADSTINCR_3; // Rpt, incDMA0CTL |= 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 sizeDMA1CTL = DMADT_5 | DMASRCINCR_3 | DMADSTINCR_3; // Rpt, incDMA1CTL |= DMAEN | DMAIE;__bis_SR_register(GIE);while(1){//P1OUT |= 0x01;// P1.0 = 1, LED onDMA0CTL |= DMAREQ;// Trigger block transferDMA1CTL |= 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 0P4OUT ^= BIT6; // Toggle P1.0 - PLACE BREAKPOINT HERE AND CHECK DMA_DST VARIABLEbreak;case 4: // DMA1IFG = DMA Channel 1P1OUT ^= BIT0;break;case 6: break; // DMA2IFG = DMA Channel 2case 8: break; // DMA3IFG = DMA Channel 3case 10: break; // DMA4IFG = DMA Channel 4case 12: break; // DMA5IFG = DMA Channel 5case 14: break; // DMA6IFG = DMA Channel 6case 16: break; // DMA7IFG = DMA Channel 7default: 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通道中断
,
Ben Qin:
有没有其他的板子能试一下?
,
?? ?:
现在手上没有
,
Ben Qin:
我推测是硬件问题,可能是板子坏了
,
?? ?:
我找到问题了,为了讲清楚问题,请先让我概述一下设计内容,系统时钟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吗?
,
Ben Qin:
?? ? 说:这个时间会很长吗?
这个不是很清楚,没有相关的数据。
?? ? 说:难道使用DMA1的时候不能使用DMA0吗?
可以的。