单片机
返回首页

MSP430使用指南32 -> SAC智能模拟组合

2020-03-30 来源:eefocus

SAC(Smart Analog Combo),即智能模拟组合,这个IP核出来的时间并不长,目前只用在了两个片子上:MSP430FR2353和MSP430FR2355。首先看一下SAC内部是个什么结构呢:

从上图可以看到,内部本质上就是一个OPA放大器,同时在运放的+和-的输入端有个选择开关,可以根据客户的需求搭建不同的电路,同时内部还集成一个12 bit的DAC模块,用于在一些使用环境下提供固定的电压,可以实现电压偏移的目的。


针对上述这个内部结构,我们进行细致的分析:


对于+输入端,有三个可以选择的通道:


00:引脚接入  


01:12 bit DAC信号  


10:内部Amp的输出,也就是其他SAC模块的输出,用于多级Amp的组合。


对于-输入端,同样也有三个可以选择的通道:


00:引脚接入(也可以选择本Amp的输出构成反馈电路,也可以直接接地)


01:可编程的增益


10:内部Amp的输出,也就是其他SAC模块的输出,用于多级Amp的组合。


那么如何使用呢,主要用在哪些方面呢:


总的一句话来说,只要是使用Amp的电路设计上,都能用到这个模块的资源,在聚焦一点的话,就是微小电流的检测,比如生物科技中的血糖仪,血氧仪,脉搏检测器等。同时也可以用于驱动一定功率的红外或者led。


下面讲述有哪几种常用的方法即连接方式:


General-Purpose Mode (通用模式)

如上图所示的通用模式,OA的正端和负端均选中位外部引脚作为输入,同时输出端不反馈,因此可直接作为一个OA使用,用户可以自己搭建外围电路。


Buffer Mode(缓冲器模式)

如上这种电路拓扑结构,是电压跟随器,电压缓冲器的连接方式(跟随器和缓冲器有一定区别,不细说),在用户要求一些输入阻抗高,输出阻抗低的情况下可以使用。


Inverting  Mode(反转模式)

反转模式,如上所示,这种电路结构应该是用户使用最多的电路了,负端作为输入,正端可以提供一个需要的偏执电压,具体公式不细说,比较简单了资料也很多。


对于正端提供的偏执电压呢,有两种方式:内部12 bitDAC和直接引入外部的电压。即位如上所示的两种结构。


Noninverting  Mode(同相模式)

这个电路拓扑是同相模式,输入端从正端输入,负端和输出通过可调节的增益相连接构成一个反馈电路。


SAC内部本质上就是运放结构,同时在输入及输出端搭配了多个选择开关,从而用户在使用过程中可以免去外部的电阻,电容等电路,节省板载空间,也可以加速用户设计。同时内部的SAC模块可以级联,进行多级放大,更便于使用。那么如何设置内部的电路结构呢?当然是操作寄存器! 下面详细讲解一下相关的寄存器设置并给出参考程序。


先整体看一下寄存器的内容,SAC模块包括6个寄存器,如下:

SACxOA

SACEN : SAC模块的使能位,1时使能所有的SAC模块,失能情况下输出位高阻状态。


OAPM : OA的模式选择,也就是可以是高速或低速的,当然高速或者低速会影响功耗,带宽,速度等,具体参数可以参考芯片的datasheet,如下图所示位FR2355的数据。

OAEN :内部OA使能,这一位用于控制SAC内部的OA模块的使能。


NMUXEN : 这一位控制着OA负端输入的使能,看内部结构框图可以看出,在OA负端输入前有两级:第一级时MUX,也就是选择输入源,第二季是使能MUX,也就是说即使选择了MUX的输入源,这个也必须使能,否则MUX与OA的负输入端会断开。


NSEL : 负端输入选择位。


PMUXEN : 这一位和负端的NMUXEN类似,控制着正端的MUX与OA的连接或断开。


PSEL : 正端输入选择位。

SACxPGA

GAIN : OA增益选择,也就是在上面讲述的图中的可调增益的设置位,有三位,配合NSEL PSEL MSEL可以实现多种模式下的增益选择。


MSEL : PGA模式的选择,控制的是如下图中的内部电路结构:

综上可以发现,电路拓扑即增益等参数与MSEL PSEL NSEL GAIN有关系,具体这些参数怎么设置呢? 下图给了一些参数的示例,在使用过程中可以根据下述资料进行寄存器的设置。

SACxDAC

SACxDAC寄存器显而易见是用来控制SAC内部那个12bit DAC模块的,那么内部这个DAC模块的电路结构是什么样子的呢?

那么我们对着这张DAC内部的结构图就可以很容易的看懂这个寄存器里每一位的含义了。


DACSREF : 这一位决定着DAC的参考电压,有两个选项:primary和secondary,每一项的参考源在芯片的datasheet中可以查看到,如下图是FR2355的信息。

DACLSEL : 从上面结构上可以看到,这一位决定着设置的DAC值是否进入DAC CORE,当设置的数据进入DAC CORE后,则会驱动相应电压输出,也就是说这一位决定着DAC内核电压改变的频率,可以是实时的,也可以是脉冲控制的。


DACDMAE : DAC内部DMA请求使能,当DAC数据更新时,如果此位使能的情况下,则会有一个DMA的请求。


DACIE : DAC中断的使能信号,在DAC数据更新时可以产生一个中断信号给CPU。


DACEN : DAC使能位。


SACxDAT

这个寄存器是用于设置DAC电压值的,DAC的输出电压值是多少呢? 根据下面这个公式进行计算:

SACxDACSTS

 

这个寄存器是DAC的状态标志寄存器,目前只有0位用于DACIFG,其他均是预留的。


DACIFG是DAC数据更新的标志位。


SACxIV

DAC中断向量寄存器,只读寄存器,和DAC内部数据更新产生的中断有关系。当产生中断时,会触发中断向量处的程序,进而可以执行用户的中断服务程序。


 


好啦,在描述完SAC的所有寄存器后,提供几个例程以供大家参考使用(MSP430FR2355):


General Purpose Mode:

#include

 

int main(void)

{

  WDTCTL = WDTPW + WDTHOLD;                 // Stop watch dog timer

 

  P1SEL0 |= BIT1 + BIT2 + BIT3;             // Select P1.1 P1.2 P1.3 OA function

  P1SEL1 |= BIT1 + BIT2 + BIT3;             // Select P1.1 P1.2 P1.3 OA function

 

  SAC0OA |= NMUXEN + PMUXEN;                // Enable negative and positive input

  SAC0OA |= OAPM;                           // Select low speed and low power mode

  SAC0OA |= SACEN + OAEN;                   // Enable SAC and OA

 

  __bis_SR_register(LPM3_bits);             // Enter LPM3

}

 

Buffer Mode:

#include

 

int main(void)

{

  WDTCTL = WDTPW + WDTHOLD;                 // Stop watch dog timer

 

  P1SEL0 |= BIT1 + BIT3;                    // Select P1.1 P1.3 as external OA function

  P1SEL1 |= BIT1 + BIT3;                    // Select P1.1 P1.3 as external OA function

 

  SAC0OA |= NMUXEN + PMUXEN + NSEL_1 + OAPM;// Enable negative and positive input

                                            // Select PGA source as OA negative input

                                            // Select low speed and low power mode

  SAC0PGA |= MSEL_1;                        // Set as Unity-Gain Buffer Mode

  SAC0OA |= SACEN + OAEN;                   // Enable SAC and OA

 

  __bis_SR_register(LPM3_bits);             // Enter LPM3

}

Inverting  Mode:

#include

 

int main(void)

{

  WDTCTL = WDTPW + WDTHOLD;                 // Stop watch dog timer

 

  // Disable the GPIO power-on default high-impedance mode

  // to activate previously configured port settings

  PM5CTL0 &= ~LOCKLPM5;

 

  // Configure reference module

  PMMCTL0_H = PMMPW_H;                    // Unlock the PMM registers

  PMMCTL2 = INTREFEN | REFVSEL_0;         // Enable internal 1.5V reference

  while(!(PMMCTL2 & REFGENRDY));          // Poll till internal reference settles

 

  P1SEL0 |= BIT1 | BIT2 | BIT3;             // Select P1.1 P1.2 P1.3 OA function

  P1SEL1 |= BIT1 | BIT2 | BIT3;             // Select P1.1 P1.2 P1.3 OA function

 

  SAC0DAC = DACSREF_1;                       // Select 1.5V int Vref as DAC reference

  SAC0DAT = 0x0FFF;                         // Set SAC DAC data to 1.5V

  SAC0DAC |= DACEN;                         // Enable DAC

  SAC0OA = NMUXEN + PMUXEN + PSEL_1 + NSEL_1;//Select positive and negative pin input

  SAC0OA |= OAPM;                           // Select low speed and low power mode

  SAC0PGA = GAIN2 + MSEL_0;                 // Set inverting PGA mode with Gain=8

  SAC0OA |= SACEN + OAEN;                   // Enable SAC and OA

 

  __bis_SR_register(LPM3_bits);             // Enter LPM3

}

Non-inverting  Mode:

#include

 

int main(void)

{

  WDTCTL = WDTPW + WDTHOLD;                 // Stop watch dog timer

 

  P1SEL0 |= BIT1 + BIT2 + BIT3;             // Select P1.1 P1.2 P1.3 OA function

  P1SEL1 |= BIT1 + BIT2 + BIT3;             // Select P1.1 P1.2 P1.3 OA function

 

  SAC0OA = NMUXEN + PMUXEN + PSEL_0 + NSEL_1;//Select positive and negative pin input

  SAC0OA |= OAPM;                           // Select low speed and low power mode

  SAC0PGA = GAIN0 + GAIN2 + MSEL_2;         // Set Non-inverting PGA mode with Gain=17

  SAC0OA |= SACEN + OAEN;                   // Enable SAC and OA

 

  __bis_SR_register(LPM3_bits);             // Enter LPM3

}

 

DAC Buffer Mode : 就是把DAC数据输出,将SAC当作DAC使用

#include

 

unsigned int DAC_data=0;

 

int main(void)

{

  WDTCTL = WDTPW + WDTHOLD;                 // Stop watch dog timer

 

  P1SEL0 |= BIT1;                           // Select P1.1 as OA0O function

  P1SEL1 |= BIT1;                           // OA is used as buffer for DAC

 

  PM5CTL0 &= ~LOCKLPM5;          // Disable the GPIO power-on default high-impedance mode

                                 // to activate previously configured port settings

 

  // Configure reference module

  PMMCTL0_H = PMMPW_H;                      // Unlock the PMM registers

  PMMCTL2 = INTREFEN | REFVSEL_2;           // Enable internal 2.5V reference

  while(!(PMMCTL2 & REFGENRDY));            // Poll till internal reference settles

 

  SAC0DAC = DACSREF_1 + DACLSEL_2 + DACIE;  // Select int Vref as DAC reference

  SAC0DAT = DAC_data;                       // Initial DAC data

  SAC0DAC |= DACEN;                         // Enable DAC

  SAC0OA = NMUXEN + PMUXEN + PSEL_1 + NSEL_1;//Select positive and negative pin input

  SAC0OA |= OAPM;                            // Select low speed and low power mode

  SAC0PGA = MSEL_1;                          // Set OA as buffer mode

  SAC0OA |= SACEN + OAEN;                    // Enable SAC and OA

 

  // Use TB2.1 as DAC hardware trigger

  TB2CCR0 = 100-1;                           // PWM Period/2

  TB2CCTL1 = OUTMOD_6;                       // TBCCR1 toggle/set

  TB2CCR1 = 50;                              // TBCCR1 PWM duty cycle

  TB2CTL = TBSSEL__SMCLK | MC_1 | TBCLR;     // SMCLK, up mode, clear TBR

 

  __bis_SR_register(LPM3_bits + GIE);        // Enter LPM3, Enable Interrupt

}

 

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)

#pragma vector = SAC0_SAC2_VECTOR

__interrupt void SAC0_ISR(void)

#elif defined(__GNUC__)

void __attribute__ ((interrupt(SAC0_SAC2_VECTOR))) SAC0_ISR (void)

#else

#error Compiler not supported!

#endif

{

  switch(__even_in_range(SAC0IV,SACIV_4))

  {

    case SACIV_0: break;

    case SACIV_2: break;

    case SACIV_4:

        DAC_data++;

        DAC_data &= 0xFFF;

        SAC0DAT = DAC_data;                 // DAC12 output positive ramp

        break;

    default: break;

  }

}

SAC0 + SAC2 级联模式:

#include

 

unsigned int adcResult;

 

int main(void)

{

  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer

 

  P1DIR |= BIT0;                            // Select P1.0 as output

  P1OUT &= ~BIT0;                           // Set P1.0 output low

 

  PM5CTL0 &= ~LOCKLPM5;       // Disable the GPIO power-on default high-impedance mode

                              // to activate previously configured port settings

 

  //Select P1.1 P1.2 P1.3 as SAC0 function

  //Select P3.1 P3.2 P3.3 as SAC2 function

  P1SEL0 |= BIT1 + BIT2 + BIT3;

  P1SEL1 |= BIT1 + BIT2 + BIT3;

  P3SEL0 |= BIT1 + BIT2 + BIT3;

  P3SEL1 |= BIT1 + BIT2 + BIT3;

 

  SAC2OA = NMUXEN + PMUXEN + PSEL_0 + NSEL_1;//Select positive and negative pin input

  SAC2OA |= OAPM;                           // Select low speed and low power mode

  SAC2PGA = GAIN1 + MSEL_2;                 // Set Non-inverting PGA mode with Gain=3

  SAC2OA |= SACEN + OAEN;                   // Enable SAC2 and OA

  SAC0OA = NMUXEN + PMUXEN + PSEL_2 + NSEL_1;//Select Pair OA source

  SAC0OA |= OAPM;                           // Select low speed and low power mode

  SAC0PGA = GAIN0 + GAIN1 + MSEL_2;         // Set Non-inverting PGA mode with Gain=5

  SAC0OA |= SACEN + OAEN;                   // Enable SAC0 and OA

 

  // Configure ADC12

  ADCCTL0 &= ~ADCENC;                       // Disable ADC

  ADCCTL0 = ADCSHT_2 | ADCON;               // ADCON, S&H=16 ADC clks

  ADCCTL1 = ADCSHP;                         // ADCCLK = MODOSC; sampling timer

  ADCCTL2 = ADCRES_2;                       // 12-bit conversion results

  ADCIE = ADCIE0;                           // Enable ADC conv complete interrupt

  ADCMCTL0 = ADCINCH_1 | ADCSREF_0;         // A1 ADC input select = OA0 output

                                            // Vref = DVCC

 

  while(1)

  {

      ADCCTL0 |= ADCENC | ADCSC;          // Sampling and conversion start

      __bis_SR_register(LPM0_bits | GIE); // Enter LPM0, ADC_ISR will force exit

      __no_operation();                   // For debug only

 

      if (adcResult > 2047)                // OA output > 1/2 VCC

          P1OUT |= BIT0;                  // Set P1.0 LED on

      else

          P1OUT &= ~BIT0;                 // Clear P1.0 LED off

  }

}

 

// ADC interrupt service routine

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)

#pragma vector=ADC_VECTOR

__interrupt void ADC_ISR(void)

#elif defined(__GNUC__)

void __attribute__ ((interrupt(ADC_VECTOR))) ADC_ISR (void)

#else

#error Compiler not supported!

#endif

{

  switch(__even_in_range(ADCIV, ADCIV_ADCIFG))

  {

      case ADCIV_NONE:

          break;

      case ADCIV_ADCOVIFG:

          break;

      case ADCIV_ADCTOVIFG:

          break;

      case ADCIV_ADCHIIFG:

          break;

      case ADCIV_ADCLOIFG:

          break;

      case ADCIV_ADCINIFG:

          break;

      case ADCIV_ADCIFG:

          adcResult = ADCMEM0;            // Read ADC memory

          __bic_SR_register_on_exit(LPM0_bits);// Exit from LPM

          break;

      default:

          break;

  }

}

SAC0 + SAC2 + eCOMP0 级联+比较器模式(SAC可以直接连接到内部比较器上)

比较器模块的使用教程,请参考我所写的其他帖子。


#include

 

unsigned int adcResult;

 

int main(void)

{

  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer

 

  P1DIR |= BIT5;                            // Select P1.5 as output

  P1OUT &= ~BIT5;                           // Set P1.5 output low

  PM5CTL0 &= ~LOCKLPM5;          // Disable the GPIO power-on default high-impedance mode

                                 // to activate previously configured port settings

 

  // Configure reference module

  PMMCTL0_H = PMMPW_H;                    // Unlock the PMM registers

  PMMCTL2 = INTREFEN | REFVSEL_0;         // Enable internal 1.5V reference

  while(!(PMMCTL2 & REFGENRDY));          // Poll till internal reference settles

 

  //Select P1.1 P1.2 P1.3 as SAC0 function

  //Select P3.1 P3.2 P3.3 as SAC2 function

  P1SEL0 |= BIT1 + BIT2 + BIT3;

  P1SEL1 |= BIT1 + BIT2 + BIT3;

  P3SEL0 |= BIT1 + BIT2 + BIT3;

  P3SEL1 |= BIT1 + BIT2 + BIT3;

 

  SAC0OA = NMUXEN + PMUXEN + PSEL_0 + NSEL_1;//Select positive and negative pin input

  SAC0OA |= OAPM;                           // Select low speed and low power mode

  SAC0PGA = GAIN0 + GAIN1 + MSEL_2;         // Set Non-inverting PGA mode with Gain=5

  SAC0OA |= SACEN + OAEN;                   // Enable SAC0 and OA0

 

  SAC2DAC = DACSREF_1;                 // Select 1.5V internal Vref as SAC2 DAC reference

  SAC2DAT = 0xAAA;                          // Set SAC2 DAC output = 1V

  SAC2DAC |= DACEN;                         // Enable SAC2 DAC

  SAC2OA = NMUXEN + PMUXEN + PSEL_1 + NSEL_1;//Select positive and negative pin input

  SAC2OA |= OAPM;                           // Select low speed and low power mode

  SAC2PGA = MSEL_1;                         // Set OA as buffer mode

  SAC2OA |= SACEN + OAEN;                   // Enable SAC2 and OA2

 

  // Setup eCOMP

  CP0CTL0 = CPPSEL_5 | CPNSEL_5;          // Select SAC0 and SAC2 output as eCOMP0 input

  CP0CTL0 |= CPPEN | CPNEN;                  // Enable eCOMP input

  CP0CTL1 |= CPIIE | CPIE;                   // Enable eCOMP dual edge interrupt

  CP0CTL1 |= CPEN | CPMSEL;                  // Turn on eCOMP, in low power mode

 

 

  __bis_SR_register(LPM3_bits | GIE);       // Enter LPM3

  __no_operation();                         // For debug

}

 

// eCOMP interrupt service routine

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)

#pragma vector=ECOMP0_ECOMP1_VECTOR

__interrupt void ECOMP0_ISR(void)

#elif defined(__GNUC__)

void __attribute__ ((interrupt(ECOMP0_ECOMP1_VECTOR))) ECOMP0_ISR (void)

#else

#error Compiler not supported!

#endif

{

    switch(__even_in_range(CP0IV, CPIV__CPIIFG))

    {

        case CPIV__NONE:

            break;

        case CPIV__CPIFG:

            P1OUT |= BIT5;                  // OA0+ input > 200mV

            break;

        case CPIV__CPIIFG:

            P1OUT &= ~BIT5;                 // OA0+ input < 200mV

            break;

        default:

            break;

    }

}

OK,到这里SAC的所有内容就讲解完了,基本常用的程序例程也已经提供,我就不进行细致的程序讲解了,使用程序过程中对应着上述的寄存器描述就能比较容易地看懂程序地配置。

进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • PIC单片机控制的遥控防盗报警器电路

  • 用数字电路CD4069制作的万能遥控轻触开关

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • 开关电源的基本组成及工作原理

  • 如何构建一个触摸传感器电路

  • 基于ICL296的大电流开关稳压器电源电路

    相关电子头条文章