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 后、DMA 不能正常工作

Guru**** 2562120 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/946722/msp430fr5994-dma-doesn-t-work-after-being-re-enabled

器件型号:MSP430FR5994

您好!

我对 这个 e2e 线程中描述的内容有类似的问题

勘误表中没有提到有关 DMA 的任何内容。 因此、我想知道我应该如何使 DMA 在被停止并重新启用后正常工作。

上下文:

-使用 ADC MEM0转换通道1。 ADC 每312.5us 由 TimerA0触发一次。

-使用 DMA 将64个连续结果移动到 SRAM 中的缓冲区。 DMA 工作正常。

-在64次传输后禁用 DMA

-使用 ADC MEM0转换通道2一次

-重新启用 DMA

-再次使用 ADC MEM0转换通道1。 使用 DMA 将64个连续结果移动到 SRAM 中的缓冲区。 此时 DMA 不起作用(没有传输发生)。

下面是我使用的代码。

#include 
#include 
#define transfer_size 64
unsigned int result_a3=0;
unsigned int result_array[100];
void InitClock ()
{
//时钟系统设置
CSCTL0_H = CSKKEY_H; //解锁 CS 寄存器
CSCTL1 = DCOFSEL_0; //将 DCO 设置为1MHz
// CSCTL2 = SELA_LFMODCLK | SELESS__DCOCLK | SELM_DCOCLK;
//设置 ACLK = 32kHz 晶振、SMCLK = MCLK = DCO
CSCTL2 = SELA_LFXTCLK | SELESS__DCOCLK | SELM_DCOCLK;
//每个器件勘误表在将频率更改为之前将分频器设置为4
//防止因过冲瞬态而超出规格运行
CSCTL3 = DIVA__4 | DIVM_4;//针对勘误表将所有相应的时钟源设置为4分频
CSCTL1 = DCOFSEL_3; //将 DCO 设置为4MHz

//延迟~10us 以使 DCO 稳定。 60个周期= 20个周期缓冲器+(10us /(1/4MHz))
_DELAY_CYCLES (100);
CSCTL3 = DIVA__1 | DIVM_1 | DIVM__1;// MCLK = 4MHz、SMCLK = 4MHz、ACLK = 4MHz
CSCTL0_H = 0; //锁定 CS 寄存器
}

空 InitTimer()
{
/*
TA0CCR0 = 1249;
TA0CCTL1 = OUTMOD_3;// TACCR1输出模式=设置/复位
TA0CCR1 = 1200; // TACCR1 PWM 占空比
TA0CTL = tassel_SMCLK | MC__UP; // SMCLK,向上计数模式*/

TA0CCTL0 = CCIE; //启用 TACCR0中断
TA0CCR0 = 1249; // ADC 的触发周期为312.5us =(4MHz/3200)

TA0CCTL1 = OUTMOD_3;// TACCR1输出模式=设置/复位
TA0CCR1 = 1200; // TACCR1是 ADC 的触发源

TA0CTL = tassel_SMCLK | MC__UP; // SMCLK,向上计数模式
}

void InitDMA()
{
/*
//配置 DMA 通道0
__data20_write_long ((uintptr_t)&DMA0SA、(uintptr_t) 0x1C20);
//源块地址
__data20_write_long ((uintptr_t)&DMA0DA、(uintptr_t) 0x1C40);
//目标单个地址
DMA0SZ = 16; //块大小
DMA0CTL = DMADD_5 | DMASRCINCR_3 | DMADSTINCR_3;// Rpt、inc *

DMACTL0 |= DMA0TSEL__ADC12IFG;
__data16_write_addr ((unsigned short)&DMA0SA、(unsigned long)&ADC12MEM0);
__data16_write_addr ((无符号短整型)&DMA0DA、(无符号长整型)&Result_array[0]);
DMA0SZ = transfer_size; // 64次转换
DMA0CTL = DMADD_4 + DMADSTINCR_3 + DMAEN;
}

void InitADC ()
{
P1SEL1 |= BIT3 + BIT4; //为 ADC 光传感器配置 P1.3 (A3)、为 ADC 电池电压配置 P1.4 (A4)
P1SEL0 |= BIT3 + BIT4;

ADC12CTL1 = 0;
ADC12CTL0 = 0;

ADC12CTL0 |= ADC12ON;//打开。 无采样或转换开始

ADC12CTL1 = ADC12PDIV__1
+ ADC12SH_1 // TA0 CCR1触发转换
+ ADC12SHP
+ ADC12CONSEQ_2;//重复单通道

ADC12CTL2 = ADC12RES_12位;

ADC12CTL3 = 0;//起始地址= MEM0

ADC12LO = 0; //比较器高阈值和低阈值
ADC12HI = 0x0FFF;

ADC12IFGR0 = 0; //清除所有挂起标志(如果有)
ADC12IFGR1 = 0;
ADC12IFGR2 = 0;

ADC12IER0 = 0;//中断被禁用
ADC12IER1 = 0;
ADC12IER2 = 0;

ADC12MCTL0 = ADC12EOS //序列结束
+ ADC12INCH_4;// A4单端

ADC12CTL0 |= ADC12ENC;//启用转换
}

void initio()
{
//配置 GPIO
P1OUT = 0;
P1DIR = BIT0|BIT5; //表示 LED

//禁用 GPIO 上电默认高阻抗模式以激活
//先前配置的端口设置
PM5CTL0 &=~LOCKLPM5;
}

//**
* main.c
*/
int main (void)
{
WDTCTL = WDTPW | WDTHOLD; //停止 WDT

InitClock();
initio();

P1OUT|= BIT5;

InitADC();
InitTimer();
InitDMA ();

//_ bis_SR_register (LPM0_bits + GIE); //输入带中断的 LPM0
// while ((ADC12IFGR0 & ADC12IFG0)=0);//等待转换完成
while (((DMA0CTL & DMAIFG)=0);//等待传输完成
_NOP();
DMA0CTL &=~DMAEN; //禁用 DMA0

//停止任何挂起的转换
ADC12CTL1 = 0;
ADC12CTL0 = 0;
_NOP();

//选择 A3
ADC12CTL0 |= ADC12ON;//打开。 无采样或转换开始
ADC12CTL1 = ADC12PDIV__1
+ ADC12SH_0 // SW 触发转换
+ ADC12SHP
+ ADC12CONSEQ_0;//单通道、单次转换

ADC12IFGR0 = 0; //清除所有挂起标志(如果有)
ADC12IFGR1 = 0;
ADC12IFGR2 = 0;

ADC12IER0 = 0;//中断被禁用
ADC12IER1 = 0;
ADC12IER2 = 0;

ADC12MCTL0 = ADC12EOS //序列结束
+ ADC12INCH_3;// A3单端

ADC12CTL0 |= ADC12ENC | ADC12SC;//启用并开始转换

while (((ADC12IFGR0 & ADC12IFG0)=0);//等待转换完成
RESULT_A3 = ADC12MEM0;
_NOP();

P1OUT&=~BIT4;

ADC12IFGR0 = 0; //清除所有挂起标志(如果有)
ADC12IFGR1 = 0;
ADC12IFGR2 = 0;

//重新初始化 DMA
DMACTL0 |= DMA0TSEL__ADC12IFG;
DMA0CTL = DMADT_4 + DMADSTINCR_3 + DMAEN;

InitADC();

while (((DMA0CTL & DMAIFG)=0);//等待传输完成
_NOP();

while (1);
}

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    最近在这里讨论过这一点、但我认为也没有结论:

    https://e2e.ti.com/support/microcontrollers/msp430/f/166/p/919200/3426334

    我可以说的是、单个转换步骤(没有 DMA)导致一些状态被路由到 DMA 单元并停留在那里、这样它就确信即使在触发器变为低电平之后、触发器也是高电平(不可能发生上升沿)。 DMALEVEL 诀窍允许它处理触发器并返回到"现实"。 我很确定这种行为是不可预料的;我不知道为什么它不被视为勘误表。

    除了 DMALEVEL 诀窍(这是相当笨拙的)之外、我想唯一的解决方法是避免它、例如也使用 DMA 进行单通道转换。