发新帖本帖赏金 5.00元(功能说明)我要提问
123下一页
返回列表
打印

TI官方例程ADC转换到DMA之全程记录--- Example_2823xAdcToDMA.c

[复制链接]
6618|40
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 我爱你的吻123 于 2015-10-30 14:19 编辑

//###########################################################################
//
// FILE:   Example_2823xAdcToDMA.c
//
// TITLE:  DSP2823x ADC To DMA
//
// ASSUMPTIONS:
前情提要:所有红色的字体都与这个文件无关,是本人自己添加的解说。
//
//    This program requires the DSP2823x header files.
//这个程序需要DSP2823x的头文件配置完全。
//    Make sure the CPU clock speed is properly defined in
//    DSP2833x_examples.h before compiling this example.
//编译这个例子之前,确定DSP2833x的时钟配置好了。
//    Connect the signals to be converted to channel A0, A1, A2, and A3.
//把信号连接到A0, A1, A2, and A3通道。
//    As supplied, this project is configured for "boot to SARAM"
//    operation.  The 2823x Boot Mode table is shown below.
这个工程要配置到从SARAM起动,2823X的起动模式已经在下表显示了。
//    For information on configuring the boot mode of an eZdsp,
//    please refer to the documentation included with the eZdsp,
//
//       $Boot_Table:
//
//         GPIO87   GPIO86     GPIO85   GPIO84
//          XA15     XA14       XA13     XA12
//           PU       PU         PU       PU
//        ==========================================
//            1        1          1        1    Jump to Flash
//            1        1          1        0    SCI-A boot
//            1        1          0        1    SPI-A boot
//            1        1          0        0    I2C-A boot
//            1        0          1        1    eCAN-A boot
//            1        0          1        0    McBSP-A boot
//            1        0          0        1    Jump to XINTF x16
//            1        0          0        0    Jump to XINTF x32
//            0        1          1        1    Jump to OTP
//            0        1          1        0    Parallel GPIO I/O boot
//            0        1          0        1    Parallel XINTF boot
//            0        1          0        0    Jump to SARAM            <- "boot to SARAM"---------------在这里配置好
//            0        0          1        1    Branch to check boot mode
//            0        0          1        0    Boot to flash, bypass ADC cal
//            0        0          0        1    Boot to SARAM, bypass ADC cal
//            0        0          0        0    Boot to SCI-A, bypass ADC cal
//                                              Boot_Table_End$
//
//
// DESCRIPTION:
//
// ADC is setup to convert 4 channels for each SOC received, with  total of 10 SOCs.
// Each SOC initiates 4 conversions.
启动转换 Start of Conversion (SOC),ADC有四个通道要通过SOC转换。


// DMA is set up to capture the data on each SEQ1_INT.  DMA will re-sort
// the data by channel sequentially, i.e. all channel0 data will be together
// all channel1 data will be together.
//DMA被设置为捕捉每个排序器的中断。DMA将按通道排序来重排所有数据。如,所有通道0的数据在一起,通道1的数据在一起。
// Code should stop in local_DINTCH1_ISR when complete
//
// Watch Variables:
//      DMABuf1
//
//###########################################################################
//
// Original source by: M.P.
//
// $TI Release: 2833x/2823x Header Files and Peripheral Examples V133 $
// $Release Date: June 8, 2012 $
//###########################################################################

#include "DSP28x_Project.h"     // Device Headerfile and Examples Include File

// ADC start parameters              ADC开始参数
#if (CPU_FRQ_150MHZ)     // Default - 150 MHz SYSCLKOUT   我们缺省用的是系统150MHZ时钟。经过分频为25MHZ.
  #define ADC_MODCLK 0x3 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 150/(2*3)   = 25.0 MHz
#endif
#if (CPU_FRQ_100MHZ)
  #define ADC_MODCLK 0x2 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 100/(2*2)   = 25.0 MHz
#endif
#define ADC_CKPS   0x1   // ADC module clock = HSPCLK/2*ADC_CKPS   = 25.0MHz/(1*2) = 12.5MHz
#define ADC_SHCLK  0xf   // S/H width in ADC module periods                        = 16 ADC clocks
#define AVG        1000  // Average sample limit               平均样本限制
#define ZOFFSET    0x00  // Average Zero offset       平均零点偏移
#define BUF_SIZE   40    // Sample buffer size            样本缓冲区大小

// Global variable for this example                 全局变量
Uint16 j=0;

#pragma DATA_SECTION(DMABuf1,"DMARAML4");
volatile Uint16 DMABuf1[40];
volatile Uint16 *DMADest;
volatile Uint16 *DMASource;

#pragma DATA_SECTION(bufferB, ”my_sect”)
char bufferB[512];
在.cmd文件中建立对应的section就可以使用了。

#pragma DATA_SECTION(函数名或全局变量名,"用户自定义在数据空间的段名");

#pragma CODE_SECTION(函数名或全局变量名,"用户自定义在程序空间的段名");

注意   

不能在函数体内声明。

必须在定义和使用前声明

#pragma可以阻止对未调用的函数的优化


interrupt void local_DINTCH1_ISR(void);   中断

void main(void)
{
   Uint16 i;
// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the DSP2833x_SysCtrl.c file.
   InitSysCtrl();时钟设置,在DSP2833x_SysCtrl.c这个文件中有相应的寄存器的值。

// Specific clock setting for this example:
   EALLOW;
   SysCtrlRegs.HISPCP.all = ADC_MODCLK;        // HSPCLK = SYSCLKOUT/ADC_MODCLK    HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 100/(2*2)   = 25.0 MHz
把ADC打开,用150M/6=25M
   EDIS;

// Step 2. Initialize GPIO:
// This example function is found in the DSP2833x_Gpio.c file and
// illustrates how to set the GPIO to it's default state.这个函数InitGpio()是要我们配置好相应的GPIO,就是说你的AD是从哪一个引脚输入的。GPIO有几个寄存器,方向寄存器,通用I/O寄存器等等。
// InitGpio();  // Skipped for this example

// Step 3. Clear all interrupts and initialize PIE vector table:
清除所有的中断,并且初始化PIE,PIE就像是一整套的组合开关,把我们的所有中断都控制了起来,你想要什么样的中断,可以按你的要求来配置。要想知道详情的,可以看我的日志中关于PIECTRL.H  和PIEVECT.H这两篇。我贴了一些图在上面。
// Disable CPU interrupts   
   DINT;
//---------------------------------------------------------------------------
//关闭CPU中断。这个DINT它是可以理解为一个汇编代码,它在这个DSP2833x_Device.h文件中定义。
Common CPU Definitions:
extern cregister volatile unsigned int IFR;
extern cregister volatile unsigned int IER;


#define  EINT   asm(" clrc INTM")
#define  DINT   asm(" setc INTM")
#define  ERTM   asm(" clrc DBGM")
#define  DRTM   asm(" setc DBGM")
#define  EALLOW asm(" EALLOW")
#define  EDIS   asm(" EDIS")
#define  ESTOP0 asm(" ESTOP0")
// Initialize the PIE control registers to their default state.
// The default state is all PIE interrupts disabled and flags
// are cleared.
// This function is found in the DSP2833x_PieCtrl.c file.
   InitPieCtrl();------------这外就是PIE的初始化的程序,接下来我会把它打开说说的。也是一种记录的过程。

// Disable CPU interrupts and clear all CPU interrupt flags:
   IER = 0x0000;
   IFR = 0x0000;--------------------------------extern cregister volatile unsigned int IFR;  extern cregister volatile unsigned int IER;这两个地方我有一点搞不明白,它的定义方式有点奇怪,涉及到编译器的自动处理。 cregister

  使用cregister关键字,当我们定义的该类型的对象与C28x的标准的控制寄存器匹配时,编译器会自动产生相关的代码去控制对应的寄存器,使得我们可以在高级编程语言C/C++中对寄存器进行控制;如果不匹配则产生编译器错误。目前可匹配此类型的寄存器包括:

IER:中断使能寄存器

IFR:中断标志寄存器

我们在这里就暂且这么理解一下吧!


// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the interrupt
// is not used in this example.  This is useful for debug purposes.
// The shell ISR routines are found in DSP2833x_DefaultIsr.c.
// This function is found in DSP2833x_PieVect.c.
   InitPieVectTable();

// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
   EALLOW;        // Allow access to EALLOW protected registers
   PieVectTable.DINTCH1= &local_DINTCH1_ISR;
   EDIS;   // Disable access to EALLOW protected registers

   IER = M_INT7 ;                                     //Enable INT7 (7.1 DMA Ch1)
   EnableInterrupts();

// Step 4. Initialize all the Device Peripherals:
// This function is found in DSP2833x_InitPeripherals.c

// InitPeripherals(); // Not required for this example     串行外设初始化
   InitAdc();  // For this example, init the ADC                     ADC寄存器初始化

// Specific ADC setup for this example:
   AdcRegs.ADCTRL1.bit.ACQ_PS = ADC_SHCLK;
   AdcRegs.ADCTRL3.bit.ADCCLKPS = ADC_CKPS;
   AdcRegs.ADCTRL1.bit.SEQ_CASC = 0;        // 0 Non-Cascaded Mode
   AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 0x1;
   AdcRegs.ADCTRL2.bit.RST_SEQ1 = 0x1;
   AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x0;
   AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x1;
   AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x2;
   AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 0x3;
   AdcRegs.ADCCHSELSEQ2.bit.CONV04 = 0x0;
   AdcRegs.ADCCHSELSEQ2.bit.CONV05 = 0x1;
   AdcRegs.ADCCHSELSEQ2.bit.CONV06 = 0x2;
   AdcRegs.ADCCHSELSEQ2.bit.CONV07 = 0x3;
   AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 3;   // Set up ADC to perform 4 conversions for every SOC

//Step 5. User specific code, enable interrupts:
  // Initialize DMA
        DMAInitialize();

        // Clear Table
   for (i=0; i<BUF_SIZE; i++)
   {
     DMABuf1 = 0;
   }


// Configure DMA Channel
    DMADest   = &DMABuf1[0];              //Point DMA destination to the beginning of the array
        DMASource = &AdcMirror.ADCRESULT0;    //Point DMA source to ADC result register base
        DMACH1AddrConfig(DMADest,DMASource);
        DMACH1BurstConfig(3,1,10);
        DMACH1TransferConfig(9,1,0);
        DMACH1WrapConfig(1,0,0,1);
        DMACH1ModeConfig(DMA_SEQ1INT,PERINT_ENABLE,ONESHOT_DISABLE,CONT_DISABLE,SYNC_DISABLE,SYNC_SRC,
                         OVRFLOW_DISABLE,SIXTEEN_BIT,CHINT_END,CHINT_ENABLE);





        StartDMACH1();



   // Start SEQ1
   AdcRegs.ADCTRL2.bit.SOC_SEQ1 = 0x1;
   for(i=0;i<10;i++){
            for(j=0;j<1000;j++){}
        AdcRegs.ADCTRL2.bit.SOC_SEQ1 = 1;    //Normally ADC will be tied to ePWM, or timed routine
   }                                             //For this example will re-start manually

}

// INT7.1
interrupt void local_DINTCH1_ISR(void)     // DMA Channel 1
{

  // To receive more interrupts from this PIE group, acknowledge this interrupt
   PieCtrlRegs.PIEACK.all = PIEACK_GROUP7;

  // Next two lines for debug only to halt the processor here
  // Remove after inserting ISR Code
   asm ("      ESTOP0");
   for(;;);
}




打赏榜单

zhangmangui 打赏了 5.00 元 2015-10-29

相关帖子

沙发
我爱你的吻123|  楼主 | 2015-10-29 16:30 | 只看该作者
我的本意是想把八路音频信号通过DSP28335的ADC采样之后,经过DMA存储到相应的空间,利用这些数据来作一点处理。这是我先打的一个前期草稿,我会逐步完善的。有没有人做过这样的工作,如果有的话,希望指点一下。

使用特权

评论回复
板凳
zhangmangui| | 2015-10-29 21:30 | 只看该作者
牛人     持续关注      感谢分享

使用特权

评论回复
地板
我爱你的吻123|  楼主 | 2015-10-29 21:34 | 只看该作者
zhangmangui 发表于 2015-10-29 21:30
牛人     持续关注      感谢分享

多谢版主,还有打赏。这不得不激励我把这个帖子好好写下去啊。谢谢了!

使用特权

评论回复
5
我爱你的吻123|  楼主 | 2015-10-29 21:40 | 只看该作者
我的这个文件是找的TI官方的ADC转DMA工程文件,我想就从这里记录我的行程吧。每个人都是可以下得到的。这是我的工程目录。
E:\ti\controlSUITE\device_support\f2833x\v132\DSP2833x_examples_ccsv4\adc_dma
有兴趣的人可以一起探讨一下啊。


通过ADC转换到DMA寄存器后,接下来会做相应的FIR,和广义自相关分析 。COME ON...

使用特权

评论回复
6
我爱你的吻123|  楼主 | 2015-10-29 22:16 | 只看该作者
我们来看看下面这个函数都有些什么东东,在工程中起了什么作用。它来自于这个文件:FILE:   DSP2833x_SysCtrl.c

1)     InitSysCtrl();


void InitSysCtrl(void)
{

   // Disable the watchdog   关闭看门狗,看门狗大家应该都清楚我就不用多说了,接下来会打开看门狗来看看的。
   DisableDog();

   // Initialize the PLL control: PLLCR and DIVSEL    初始化锁相环时钟控制,PLLCR,  DIVSEL。喔这两个又是什么东西呢。 我们也要搞清楚。它告诉我们,这两个东东在DSP2833x_Examples.h这个头文件里面定义了。我们也要查清楚。
   // DSP28_PLLCR and DSP28_DIVSEL are defined in DSP2833x_Examples.h
   InitPll(DSP28_PLLCR,DSP28_DIVSEL);

   // Initialize the peripheral clocks    初始化串行外设的时钟,也就是说一切都是时钟,没有时钟我们不能动,我们都不能吃饭了。这就是体现了一种叫做一切行动听指挥的味道。我有一种想法就是,数字信号处理我认为一切都是波,各种波的变换。而数字信号处理器则一切都是时钟,没有时钟不能干活。
   InitPeripheralClocks();
}

使用特权

评论回复
7
我爱你的吻123|  楼主 | 2015-10-29 22:35 | 只看该作者
1.1)接着上面的函数来说。
    DisableDog();
上面的这个函数来自于DSP2833x_SysCtrl.c这个文件。
// Example: DisableDog://---------------------------------------------------------------------------
// This function disables the watchdog timer.喔 ,这个函数的意思就是关闭小狗。不让小狗叫了。


void DisableDog(void)
{
    EALLOW;
    SysCtrlRegs.WDCR= 0x0068;
    EDIS;

}
;    WDCR 看门狗控制器,这里有一个很应该注意的问是,这个相应的校验位(位5--3)必须是“101”,要不然的话会拒绝访问并会立即触发复位。那么0x0068  展开是                   0000.0000.0110.1000(位5--3)正好是101.而第六位为1时,是禁止看门狗。到这里大功告成,看门狗禁止了。小狗睡觉去了。


使用特权

评论回复
8
我爱你的吻123|  楼主 | 2015-10-29 22:37 | 只看该作者
1.2)InitPll(DSP28_PLLCR,DSP28_DIVSEL);
明天从这个开始,今天 有点累了。先睡觉去了。。。。。。。

使用特权

评论回复
9
我爱你的吻123|  楼主 | 2015-10-30 12:00 | 只看该作者
继续盖楼。
1.2)InitPll(DSP28_PLLCR,DSP28_DIVSEL);

这个函数展开就是这么一大段函数体,我们来一一了解下。
void InitPll(Uint16 val, Uint16 divsel)
{

   // Make sure the PLL is not running in limp mode        确保锁相环没有运行在软模式

这个是指锁相环的缓慢变化模式,对应的滤波器及电流变小。

DSP28_SysCtrl.h这个头文件中定义的寄存器主要与系统控制相关,包括高速外设时钟预分频器寄存器HISPCP,低速外设时钟预分频寄存器LOSPCP,外设时钟控制寄存器PCLKCR,低功耗模式控制寄存器LPMCR0,低功耗模式控制寄存器LPMCR1,PLL控制寄存器PLLCR,系统控制与状态寄存器SCSR,看门狗计数器寄存器WDCNTR,看门狗复位密钥寄存器WDKEY,看门狗控制寄存器WDCR,128为加密密匙寄存器,加密状态与控制寄存器CSMSCR,128位加密密码寄存器,Flash选项寄存器FOPT,Flash功率模式寄存器FPWR,状态寄存器FSTATUS,Flash休眠到待机等待寄存器FSTDBYWAIT,Flash待机到活动寄存器FACTIVEWAIT,Flash读取存储状态寄存器FBANKWAIT,OTP读取存储状态寄存器FOTPWAIT。

上面提到所有寄存器被分为了三组:系统控制寄存器组SysCtrlRegs,代码保护寄存器组CsmRegs,代码保护密码寄存器组CsmPwl,Flash寄存器组FlashRegs。


  



锁相环的设置由函数InitPll(DSP28_PLLCR,DSP28_DIVSEL)来完成,其中
DSP28_PLLCR、DSP28_DIVSEL分别在头文件中用宏定义赋值为10、2,这样系统的时钟频率就为150M(外部晶振30M)。InitPll(Uint16 val, Uint16 divsel)的函数体如下:



if (SysCtrlRegs.PLLSTS.bit.MCLKSTS != 0)
   { Uint16 MCLKSTS:1;      // 3     Missing clock status bit          丢失时钟状态位
             这个位,是PLL时钟寄存器中关于是否存在的标志。如果它不等于0则执行下面这句话。
      // Missing external clock has been detected
      // Replace this line with a call to an appropriate
      // SystemShutdown(); function.
      asm("        ESTOP0");
ESTOP0这个是2812的一个汇编指令,是用于仿真的,它有两个方面的知识:1、当用仿真器连接时如果ESTOP0置位(ESTOP0=1),那么整个DSP停止运行。1 S' R62、当不用仿真程序时,在程序中写这条指令相当于NOP(空指令),只是占了CPU的一个周期而已
   }

   // DIVSEL MUST be 0 before PLLCR can be changed from
   // 0x0000. It is set to 0 by an external reset XRSn
   // This puts us in 1/4
   if (SysCtrlRegs.PLLSTS.bit.DIVSEL != 0)
   {
       EALLOW;
       SysCtrlRegs.PLLSTS.bit.DIVSEL = 0;
       EDIS;
   }

   // Change the PLLCR
   if (SysCtrlRegs.PLLCR.bit.DIV != val)
   {

      EALLOW;
      // Before setting PLLCR turn off missing clock detect logic
      SysCtrlRegs.PLLSTS.bit.MCLKOFF = 1;
      SysCtrlRegs.PLLCR.bit.DIV = val;
      EDIS;

      // Optional: Wait for PLL to lock.
      // During this time the CPU will switch to OSCCLK/2 until
      // the PLL is stable.  Once the PLL is stable the CPU will
      // switch to the new PLL value.
      //
      // This time-to-lock is monitored by a PLL lock counter.
      //
      // Code is not required to sit and wait for the PLL to lock.
      // However, if the code does anything that is timing critical,
      // and requires the correct clock be locked, then it is best to
      // wait until this switching has completed.

      // Wait for the PLL lock bit to be set.

      // The watchdog should be disabled before this loop, or fed within
      // the loop via ServiceDog().

          // Uncomment to disable the watchdog
      DisableDog();

      while(SysCtrlRegs.PLLSTS.bit.PLLLOCKS != 1)
      {
              // Uncomment to service the watchdog
          // ServiceDog();
      }

      EALLOW;
      SysCtrlRegs.PLLSTS.bit.MCLKOFF = 0;
      EDIS;
以上程序中含有“.bit”的为寄存器的位操作,“.bit”之前的为具体的寄存器。在DSP的程序体系中,将寄存器定义为结构体,有些结构体中还包含联合体。上述代码中,asm("      ESTOP0")表示停止仿真。EALLOW一般和EDIS配套使用,EALLOW就是将该标志位置位,允许对受保护的寄存器操作,在对受保护的寄存器操作之后,用EDIS恢复寄存器的被保护状态。
    }

    // If switching to 1/2
        if((divsel == 1)||(divsel == 2))
        {
                EALLOW;
            SysCtrlRegs.PLLSTS.bit.DIVSEL = divsel;
            EDIS;
        }


        // NOTE: ONLY USE THIS SETTING IF PLL IS BYPASSED (I.E. PLLCR = 0) OR OFF
        // If switching to 1/1
        // * First go to 1/2 and let the power settle
        //   The time required will depend on the system, this is only an example
        // * Then switch to 1/1
        if(divsel == 3)
        {
                EALLOW;
            SysCtrlRegs.PLLSTS.bit.DIVSEL = 2;
            DELAY_US(50L);
            SysCtrlRegs.PLLSTS.bit.DIVSEL = 3;
            EDIS;
    }
}




这个地方啰嗦的写了好多,总而言之就是配置PLL锁相环,给ADC配置为25MHZ.如果有不清楚的地方,我的日志里面也整理了一些资料。可以去看看。

使用特权

评论回复
10
我爱你的吻123|  楼主 | 2015-10-30 12:58 | 只看该作者
在TI给的这个Example_2823xAdcToDMA.c工程文件里面,有一个奇怪的问题,这段话是这样写的。
// Step 2. Initialize GPIO:
// This example function is found in the DSP2833x_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
// InitGpio();  // Skipped for this example



也就是说初始化IO是屏蔽了的。我的问题是,那么我的模拟信号是从哪几个IO口输入进去的呢?


这个暂且放下。我们先讲一下这个InitPieCtrl();函数!




使用特权

评论回复
11
我爱你的吻123|  楼主 | 2015-10-30 13:20 | 只看该作者
我们来分解一下关于PIE的初始化函数。

InitPieCtrl();
// This function initializes the PIE control registers to a known state.
//这个函数是把我们所有的PIE全部关闭的,我们这个片子上的所有的中断都是基于这个开关组合的。现在的情况是首先全部关闭掉,再依照自己的需求打开相应的中断。
void InitPieCtrl(void)
{
    // Disable Interrupts at the CPU level:
    DINT;

    // Disable the PIE
    PieCtrlRegs.PIECTRL.bit.ENPIE = 0;

        // Clear all PIEIER registers:           清除所有中断使能位
        PieCtrlRegs.PIEIER1.all = 0;
        PieCtrlRegs.PIEIER2.all = 0;
        PieCtrlRegs.PIEIER3.all = 0;       
        PieCtrlRegs.PIEIER4.all = 0;
        PieCtrlRegs.PIEIER5.all = 0;
        PieCtrlRegs.PIEIER6.all = 0;
        PieCtrlRegs.PIEIER7.all = 0;
        PieCtrlRegs.PIEIER8.all = 0;
        PieCtrlRegs.PIEIER9.all = 0;
        PieCtrlRegs.PIEIER10.all = 0;
        PieCtrlRegs.PIEIER11.all = 0;
        PieCtrlRegs.PIEIER12.all = 0;

        // Clear all PIEIFR registers:         清除所有中断标志位
        PieCtrlRegs.PIEIFR1.all = 0;
        PieCtrlRegs.PIEIFR2.all = 0;
        PieCtrlRegs.PIEIFR3.all = 0;       
        PieCtrlRegs.PIEIFR4.all = 0;
        PieCtrlRegs.PIEIFR5.all = 0;
        PieCtrlRegs.PIEIFR6.all = 0;
        PieCtrlRegs.PIEIFR7.all = 0;
        PieCtrlRegs.PIEIFR8.all = 0;
        PieCtrlRegs.PIEIFR9.all = 0;
        PieCtrlRegs.PIEIFR10.all = 0;
        PieCtrlRegs.PIEIFR11.all = 0;
        PieCtrlRegs.PIEIFR12.all = 0;


}       

使用特权

评论回复
12
我爱你的吻123|  楼主 | 2015-10-30 13:47 | 只看该作者
在这个InitPieVectTable();函数里面我们来看看它做了哪些事情。

/ Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the interrupt
// is not used in this example.  This is useful for debug purposes.
// The shell ISR routines are found in DSP2833x_DefaultIsr.c.
// This function is found in DSP2833x_PieVect.c.
2)  InitPieVectTable();

// InitPieVectTable:
//---------------------------------------------------------------------------
// This function initializes the PIE vector table to a known state.
// This function must be executed after boot time.
//

void InitPieVectTable(void)
{
        int16        i;
        Uint32 *Source = (void *) &PieVectTableInit;
        Uint32 *Dest = (void *) &PieVectTable;
               
        EALLOW;       
        for(i=0; i < 128; i++)            这是一个重点要关注的点,这几句话的意思是指针赋值,就是把SOURCE的源指针赋给DEST的目的指针。我们知道PIE有96个中断向量,而PieVectTable这是一个全局的变量,它在这个DSP2833x_GlobalVariableDefs.c文件中定义了的。暂且 把这里意思理解为把中断向量表全局化吧。我也不知道对不对。 有知道的朋友可以讲解一下。
                *Dest++ = *Source++;       
        EDIS;

        // Enable the PIE Vector Table
        PieCtrlRegs.PIECTRL.bit.ENPIE = 1;        打开PIE控制器。我们可以把这个理解为一个总开关吧。
                       
}

//===========================================================================
// End of file.
//===========================================================================


使用特权

评论回复
13
我爱你的吻123|  楼主 | 2015-10-30 14:04 | 只看该作者
这个地方是开启DMA中断的程序。我们知道DMA在PIE第7组上,它有DMA通道。我们开了第七组的通道1.
Group 7 PIE Vectors
      DINTCH1_ISR,     // 7.1  DMA channel 1   
      DINTCH2_ISR,     // 7.2  DMA channel 2
      DINTCH3_ISR,     // 7.3  DMA channel 3      
      DINTCH4_ISR,     // 7.4  DMA channel 4           
      DINTCH5_ISR,     // 7.5  DMA channel 5      
      DINTCH6_ISR,     // 7.6  DMA channel 6      
      rsvd_ISR,        // 7.7      
      rsvd_ISR,        // 7.8   

// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
   EALLOW;        // Allow access to EALLOW protected registers
   PieVectTable.DINTCH1= &local_DINTCH1_ISR;
   EDIS;   // Disable access to EALLOW protected registers

   IER = M_INT7 ;                                     //Enable INT7 (7.1 DMA Ch1)

使用特权

评论回复
14
我爱你的吻123|  楼主 | 2015-10-30 14:18 | 只看该作者
EnableInterrupts();


void EnableInterrupts()
{

    // Enable the PIE
    PieCtrlRegs.PIECTRL.bit.ENPIE = 1;
这里是把PIE总中断开关打开了
                   
        // Enables PIE to drive a pulse into the CPU
        PieCtrlRegs.PIEACK.all = 0xFFFF;  
PIEACK这是一个中断应答位,第一个PIE 中断都有一上应答们,情况是这样的:
如果PIEACK=1则CPU会等待该中断,如果PIEACK=0;则PIE进入CPU中断。
-------------------这个地方一知道我解释的对不对,如果有问题请各位指出来。以免误导后来者。
        // Enable Interrupts at the CPU level
    EINT;

}


使用特权

评论回复
15
我爱你的吻123|  楼主 | 2015-10-30 15:14 | 只看该作者
本帖最后由 我爱你的吻123 于 2015-10-30 15:25 编辑

在这个工程中,这是第四步,也就是我们所说的ADC初始化。我们来看看,这个函数到底做了点啥!

InitAdc();  // For this example, init the ADC




//---------------------------------------------------------------------------
// InitAdc:
//---------------------------------------------------------------------------
// This function initializes ADC to a known state.
//
void InitAdc(void)
{
    extern void DSP28x_usDelay(Uint32 Count);


    // *IMPORTANT*
        // The ADC_cal function, which  copies the ADC calibration values from TI reserved
        // OTP into the ADCREFSEL and ADCOFFTRIM registers, occurs automatically in the
        // Boot ROM. If the boot ROM code is bypassed during the debug process, the
        // following function MUST be called for the ADC to function according
        // to specification. The clocks to the ADC MUST be enabled before calling this
        // function.
        // See the device data manual and/or the ADC Reference
        // Manual for more information.

            EALLOW;
                SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1;
要想知道这句话是什么意思 ,我们要先知道SysCtrlRegs是个什么,这个呢中文叫做系统控制寄存器,一般情况下,带系统两字就是非常牛的东东了。那么它真的很牛,什么高速、低速、串行外设都归它管。
             接下来PCLKCR0这个叫 Peripheral clock control register 串行外设时钟控制器,注意这时有两个啊,一个0、一个1.不同的外设挂在不同的上面,在这里我们就不深究了,感兴趣的同学可以自己查一下资料啊。
              这个PCLKCR寄存器啊,控制了很多东东,如MCBSPENCLK,SCIA-BENCLK,SPIAENCLK,
EVA-BENCLK,ADCENCLK.等等。
       我们这里就用了ADCENCLK,如果ADCENCLK=1。则使能ADC外设时钟HSPCLK,那么是多少呢,150/4=25MHZ.  所以说解释了这么长时间,我们就是给ADC加上了时钟。
                ADC_cal();
                EDIS;




    // To powerup the ADC the ADCENCLK bit should be set first to enable
    // clocks, followed by powering up the bandgap, reference circuitry, and ADC core.
    // Before the first conversion is performed a 5ms delay must be observed
        // after power up to give all analog circuits time to power up and settle

    // Please note that for the delay function below to operate correctly the
        // CPU_RATE define statement in the DSP2833x_Examples.h file must
        // contain the correct CPU clock period in nanoseconds.

    AdcRegs.ADCTRL3.all = 0x00E0;  // Power up bandgap/reference/ADC circuits
上面AdcRegs.ADCTRL3这个真的要好好说说,这是我们能够使用ADC的关键啊。这个叫ADC寄存器。我们先来看张图啊。


这里详细介绍了这个寄存器的所有功能啊。不知道各位看不看的清楚。如果我们按照上面的0X00E0展开,则为0000.0000.1110.0000.大家注意了,这些个是什么意思呢。就是说, 我们采用顺序采样模式,采用相应的分频模式,ADC电源控制上电,ADC带隙电源控制上电,ADC参考控制电源上电,ADC选内部电源为参考。
到此,这个寄存器分解完毕。真是不简单啊。




    DELAY_US(ADC_usDELAY);         // Delay before converting ADC channels---这是一个延时函数,我就不细表了。
}

//===========================================================================
// End of file.

//===========================================================================

使用特权

评论回复
16
我爱你的吻123|  楼主 | 2015-10-30 15:42 | 只看该作者
我们既然是做ADC相关的程序编写,那么就啰嗦一点把这个ADC_REGS也搞清楚。先看几个图。






struct ADC_REGS {
    union ADCTRL1_REG      ADCTRL1;       // ADC Control 1
    union ADCTRL2_REG      ADCTRL2;       // ADC Control 2
    union ADCMAXCONV_REG   ADCMAXCONV;    // Max conversions   最大转换通道,比如你想转换3个通道,那么这个值就等于2. 0.1.2
    union ADCCHSELSEQ1_REG ADCCHSELSEQ1;  // Channel select sequencing control 1
    union ADCCHSELSEQ2_REG ADCCHSELSEQ2;  // Channel select sequencing control 2
    union ADCCHSELSEQ3_REG ADCCHSELSEQ3;  // Channel select sequencing control 3
    union ADCCHSELSEQ4_REG ADCCHSELSEQ4;  // Channel select sequencing control 4
    union ADCASEQSR_REG    ADCASEQSR;     // Autosequence status register
    Uint16                 ADCRESULT0;    // Conversion Result Buffer 0
    Uint16                 ADCRESULT1;    // Conversion Result Buffer 1
    Uint16                 ADCRESULT2;    // Conversion Result Buffer 2
    Uint16                 ADCRESULT3;    // Conversion Result Buffer 3
    Uint16                 ADCRESULT4;    // Conversion Result Buffer 4
    Uint16                 ADCRESULT5;    // Conversion Result Buffer 5
    Uint16                 ADCRESULT6;    // Conversion Result Buffer 6
    Uint16                 ADCRESULT7;    // Conversion Result Buffer 7
    Uint16                 ADCRESULT8;    // Conversion Result Buffer 8
    Uint16                 ADCRESULT9;    // Conversion Result Buffer 9
    Uint16                 ADCRESULT10;   // Conversion Result Buffer 10
    Uint16                 ADCRESULT11;   // Conversion Result Buffer 11
    Uint16                 ADCRESULT12;   // Conversion Result Buffer 12
    Uint16                 ADCRESULT13;   // Conversion Result Buffer 13
    Uint16                 ADCRESULT14;   // Conversion Result Buffer 14
    Uint16                 ADCRESULT15;   // Conversion Result Buffer 15
    union ADCTRL3_REG      ADCTRL3;       // ADC Control 3  
    union ADCST_REG        ADCST;         // ADC Status Register
    Uint16                                   rsvd1;
    Uint16                 rsvd2;
    union ADCREFSEL_REG    ADCREFSEL;     // Reference Select Register
    union ADCOFFTRIM_REG   ADCOFFTRIM;    // Offset Trim Register
};

使用特权

评论回复
17
我爱你的吻123|  楼主 | 2015-10-30 16:12 | 只看该作者

#define ADC_CKPS   0x1   // ADC module clock = HSPCLK/2*ADC_CKPS   = 25.0MHz/(1*2) = 12.5MHz
#define ADC_SHCLK  0xf   // S/H width in ADC module periods                        = 16 ADC clocks
#define AVG        1000  // Average sample limit
#define ZOFFSET    0x00  // Average Zero offset
#define BUF_SIZE   40    // Sample buffer size
// Specific ADC setup for this example:
   AdcRegs.ADCTRL1.bit.ACQ_PS = ADC_SHCLK;这里面ADC_SHCLK=0xf,就是说这里为四个1,这个位是采样时间预定标。就是说采样的开关时间。如果说学习过信号与系统,就会知道这个是什么意思了。就是说我把一段连续的信号变为离散的信号 ,我从什么时候开什么时候关,形成一个截断区间。这是我的理解。
   AdcRegs.ADCTRL3.bit.ADCCLKPS = ADC_CKPS;这个我上面讲过, 这里ADC_CKPS=0x1.就是两分频。25MHZ分为2,为12.5MHZ.
   AdcRegs.ADCTRL1.bit.SEQ_CASC = 0;        // 0 Non-Cascaded Mode           这里这个位为0,则为双排序模式。  为1则为级联模式。

   AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 0x1;             中断使能SEQ1
   AdcRegs.ADCTRL2.bit.RST_SEQ1 = 0x1;                  将该位写1立即奖排序器复位为一个初始的“预触发”状态。
   AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x0;
   AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x1; ----------这些就是排序器要转换的通道了。分为两组,每组四个。
   AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x2;
   AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 0x3;
   AdcRegs.ADCCHSELSEQ2.bit.CONV04 = 0x0;
   AdcRegs.ADCCHSELSEQ2.bit.CONV05 = 0x1;
   AdcRegs.ADCCHSELSEQ2.bit.CONV06 = 0x2;
   AdcRegs.ADCCHSELSEQ2.bit.CONV07 = 0x3;
   AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 3;   // Set up ADC to perform 4 conversions for every SOC

每个SOC最大转换通道数。这里为四个。

使用特权

评论回复
18
我爱你的吻123|  楼主 | 2015-10-30 16:44 | 只看该作者
这里是第五步了,我们要初始化DMA了。离目标越来越近了,有点小激动。。。。。


//Step 5. User specific code, enable interrupts:
  // Initialize DMA
        DMAInitialize();

// This function initializes the DMA to a known state.
//               这个函数把DMA初始到确切的状态。
void DMAInitialize(void)
{
        EALLOW;

        // Perform a hard reset on DMA
        DmaRegs.DMACTRL.bit.HARDRESET = 1;            DMA  硬重启位  
    asm (" nop"); // one NOP required after HARDRESET

        // Allow DMA to run free on emulation suspend            DEBUG  模式位
                                                                         //        0     halt after current read-write operation      0  停止随后的读写操作
                                                                        //        1     continue running                                  1       继续执行。
        DmaRegs.DEBUGCTRL.bit.FREE = 1;

        EDIS;
}


使用特权

评论回复
19
我爱你的吻123|  楼主 | 2015-10-30 16:49 | 只看该作者
// Clear Table
   for (i=0; i<BUF_SIZE; i++)
   {
     DMABuf1 = 0;
   }


这个地方很明确,我们是想把BUF清空,免得有其它乱码在这里面存在。

使用特权

评论回复
20
我爱你的吻123|  楼主 | 2015-10-30 17:13 | 只看该作者
volatile Uint16 *DMADest;          DMA目标地址指针
volatile Uint16 *DMASource;         DMA源地址指针  
interrupt void local_DINTCH1_ISR(void);
上面 这些是我们在文件中声明了一些变量。




void DMACH1AddrConfig(volatile Uint16 *DMA_Dest,volatile Uint16 *DMA_Source)
        源地址有两个,一个A为用于传输时(随每个字节递增),另一个B作为返回的备份(当一帧结束后,重新装载入A)
        目的地址有两个,一个A为用于传输时(随每个字节递增),另一个B作为返回的备份(当一帧结束后,重新装载入A)
        每次启动DMA相应通道,都会把B装载入A
        void DMACH1BurstConfig(Uint16 bsize, int16 srcbstep, int16 desbstep)
        Bsize: 每一个脉冲传递的字的个数,实际脉冲数为bsize+1
        Srcbstep:每传递一个字后,源地址A增量
        Desbstep:每传递一个字后,目的地址A增量

        void DMACH1TransferConfig(Uint16 tsize, int16 srctstep, int16 deststep)
        Tsize:每一帧的脉冲个数,脉冲递减到0时(即一帧传递完成,也是DMA传递完成),产生DMA中断。实际帧数为tsize+1
        Srctstep:每个脉冲的最后一个字传递结束后,源地址A增量
        Deststep:每个脉冲的最后一个字传递结束后,目的地址A增量

        void DMACH1WrapConfig(Uint16 srcwsize, int16 srcwstep, Uint16 deswsize, int16 deswstep)
        Srcwsize:当已经传递的脉冲数为srcwsize+1的整数倍时,源地址(B)增加srcwstep(常为0),并装载入源地址A
        Deswsize:当已经传递的脉冲数为deswsize+1的整数倍时,目的地址(B)增加deswstep(常为0),并装载入目的地址A

        void DMACH1ModeConfig(Uint16 persel, Uint16 perinte, Uint16 oneshot, Uint16 cont, Uint16 synce, Uint16 syncsel, Uint16 ovrinte, Uint16 datasize, Uint16 chintmode, Uint16 chinte)
        Persel:选择触发DMA的外设中断源
        Perinte:外设中断使能,
        Oneshot:使能时,外设产生一次中断,就能够把一帧传递完。禁止,外设产生一次中断,只能传递一个脉冲
        Cont:使能时,每次DMA结束后,需要再次启动DMA时,就不需要调用void StartDMACH1(void)。禁止时,重启DMA,需要调用void StartDMACH1(void)
        Datasize:设置每个字是16位或者32位
        Chintmode:设置DMA中断是在DMA启动或者结束时产生
        Chinte:DMA相应通道的中断使能(外设级)。
        注:Perinte和Chinte同时使能时,才能进入DMA通道中断
        仅Perinte使能,可以传输数据,但是不进入通道的中断程序

        void StartDMACH1(void)
        首次启动DMA,若Cont为禁止,每次DMA结束后,需要再次启动DMA时需要调用
        只开启相应用于触发的外设级中断,不开启PIE对应位,则能够触发DMA而不触发CPU的中断程序
        经过DMACH1ModeConfig配置的中断,DMA会自动清除相应外设级的中断标志位,不用程序清除


上面的这些说明是我找的一些资料
// Configure DMA Channel         配置DMA通道
        DMADest   = &DMABuf1[0];              //Point DMA destination to the beginning of the array       这里指出我们的目标地址是在DMABuf1[0]这个寄存器
        DMASource = &AdcMirror.ADCRESULT0;    //Point DMA source to ADC result register base      源地址是这ADCRESULT0寄存器
        DMACH1AddrConfig(DMADest,DMASource);
        DMACH1BurstConfig(3,1,10);
Bsize: 每一个脉冲传递的字的个数,实际脉冲数为bsize+1
        Srcbstep:每传递一个字后,源地址A增量
        Desbstep:每传递一个字后,目的地址A增量        那么(3,1,10),每一个脉冲传递的个数为3,每传递一个字后,源地地址加1,目标地址加10;

DMACH1TransferConfig(9,1,0);
        Tsize:每一帧的脉冲个数,脉冲递减到0时(即一帧传递完成,也是DMA传递完成),产生DMA中断。实际帧数为tsize+1
        Srctstep:每个脉冲的最后一个字传递结束后,源地址A增量
        Deststep:每个脉冲的最后一个字传递结束后,目的地址A增量

        请按上面对号入座。!!!!!!!!!
DMACH1WrapConfig(1,0,0,1);
        void DMACH1WrapConfig(Uint16 srcwsize, int16 srcwstep, Uint16 deswsize, int16 deswstep)
        Srcwsize:当已经传递的脉冲数为srcwsize+1的整数倍时,源地址(B)增加srcwstep(常为0),并装载入源地址A
        Deswsize:当已经传递的脉冲数为deswsize+1的整数倍时,目的地址(B)增加deswstep(常为0),并装载入目的地址A
        请按上面对号入座。!!!!!!!!!
DMACH1ModeConfig(DMA_SEQ1INT,PERINT_ENABLE,ONESHOT_DISABLE,CONT_DISABLE,SYNC_DISABLE,SYNC_SRC,
                         OVRFLOW_DISABLE,SIXTEEN_BIT,CHINT_END,CHINT_ENABLE);
void DMACH1ModeConfig(Uint16 persel, Uint16 perinte, Uint16 oneshot, Uint16 cont, Uint16 synce, Uint16 syncsel, Uint16 ovrinte, Uint16 datasize, Uint16 chintmode, Uint16 chinte)
        Persel:选择触发DMA的外设中断源
        Perinte:外设中断使能,
        Oneshot:使能时,外设产生一次中断,就能够把一帧传递完。禁止,外设产生一次中断,只能传递一个脉冲
        Cont:使能时,每次DMA结束后,需要再次启动DMA时,就不需要调用void StartDMACH1(void)。禁止时,重启DMA,需要调用void StartDMACH1(void)
        Datasize:设置每个字是16位或者32位
        Chintmode:设置DMA中断是在DMA启动或者结束时产生
        Chinte:DMA相应通道的中断使能(外设级)。
        注:Perinte和Chinte同时使能时,才能进入DMA通道中断
        仅Perinte使能,可以传输数据,但是不进入通道的中断程序
请按上面对号入座。!!!!!!!!!

void DMACH1AddrConfig(volatile Uint16 *DMA_Dest,volatile Uint16 *DMA_Source)
{
        EALLOW;
        // Set up SOURCE address:
        DmaRegs.CH1.SRC_BEG_ADDR_SHADOW = (Uint32)DMA_Source;        // Point to beginning of source buffer
        DmaRegs.CH1.SRC_ADDR_SHADOW =     (Uint32)DMA_Source;


        // Set up DESTINATION address:
        DmaRegs.CH1.DST_BEG_ADDR_SHADOW = (Uint32)DMA_Dest;            // Point to beginning of destination buffer
        DmaRegs.CH1.DST_ADDR_SHADOW =     (Uint32)DMA_Dest;
这个也好理解,就是源地址与目标地址的配置。
        EDIS;
}



void DMACH1BurstConfig(Uint16 bsize, int16 srcbstep, int16 desbstep)
{
        EALLOW;


        // Set up BURST registers:
        DmaRegs.CH1.BURST_SIZE.all = bsize;                        // Number of words(X-1) x-ferred in a burst
        DmaRegs.CH1.SRC_BURST_STEP = srcbstep;                            // Increment source addr between each word x-ferred
        DmaRegs.CH1.DST_BURST_STEP = desbstep;              // Increment dest addr between each word x-ferred




        EDIS;
}


使用特权

评论回复
发新帖 本帖赏金 5.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:本工作室是专业电子类设计开发团队,团队成员全为从事51\DSP\ ARM\fpga类嵌入式开发和图像处理、机器学习等相关算法研究多年的软、硬件开发工程师,已与全国几十家客户成功合作,可以长期提供技术支持,承接各类相关项目开发与咨询服务。 QQ:1746430162

37

主题

836

帖子

60

粉丝