This content is originally created by EEWORLD forum user Qi IC Kan MCU . If you want to reprint or use it for commercial purposes, you must obtain the author's consent and indicate the source
SAC ( Smart Analog Combo ) is a smart analog combination. This IP core has not been out for a long time and is currently only used in two chips: MSP430FR2353 and MSP430FR2355 . First, let's take a look at the internal structure of SAC :
As can be seen from the above figure, the internal structure is essentially an OPA amplifier. At the same time, there is a selection switch at the + and - input ends of the op amp, which can be used to build different circuits according to customer needs. At the same time, a 12-bit DAC module is also integrated inside to provide a fixed voltage in some usage environments, which can achieve the purpose of voltage offset.
We conduct a detailed analysis of the above internal structure:
For the + input, there are three channels to choose from:
00 : Pin access
01 : 12-bit DAC signal
10 : Output of internal Amp , that is, the output of other SAC modules, used for the combination of multi-stage Amp .
For the - input, there are also three channels to choose from:
00 : Pin access (you can also select the output of this Amp to form a feedback circuit, or directly connect to ground)
01 : Programmable gain
10 : Output of internal Amp , that is, the output of other SAC modules, used for the combination of multi-stage Amp .
So how to use it, what are the main uses:
In a word, as long as the circuit design uses Amp , the resources of this module can be used. If we focus on it, it is the detection of tiny currents, such as blood glucose meters, blood oximeters, pulse detectors, etc. in biotechnology. It can also be used to drive infrared or LEDs of a certain power .
The following are some common methods or connection methods:
As shown in the general mode above, the positive and negative ends of the OA both select the middle external pin as input, and the output end does not feedback, so it can be used directly as an OA , and users can build peripheral circuits by themselves.
The circuit topology shown above is a voltage follower, a voltage buffer connection method (there are certain differences between followers and buffers, which will not be discussed in detail). It can be used when the user requires high input impedance and low output impedance.
Inversion mode, as shown above, this circuit structure should be the most commonly used circuit by users. The negative end is used as input, and the positive end can provide a required bias voltage. The specific formula will not be explained in detail, as it is relatively simple and there is a lot of information.
There are two ways to provide bias voltage at the positive terminal: internal 12-bit DAC and direct introduction of external voltage, which are the two structures shown above.
This circuit topology is in the same phase mode, the input is from the positive end, and the negative end and the output are connected through an adjustable gain to form a feedback circuit.
The SAC is essentially an op amp structure, and multiple selection switches are provided at the input and output ends, so that users can avoid external resistors, capacitors and other circuits during use, saving on-board space and speeding up user design. At the same time, the internal SAC modules can be cascaded for multi-stage amplification, which is more convenient to use. So how to set the internal circuit structure? Of course, it is to operate the registers! The following is a detailed explanation of the relevant register settings and a reference program.
First, let's take a look at the contents of the registers. The SAC module includes 6 registers, as follows:
SACEN: Enable bit of SAC module. When 1 , all SAC modules are enabled. When disabled, the output is in high-impedance state.
OAPM: OA mode selection, that is, it can be high speed or low speed. Of course, high speed or low speed will affect power consumption, bandwidth, speed, etc. For specific parameters, please refer to the chip datasheet , as shown in the figure below for the data of FR2355 .
OAEN : Internal OA enable, this bit is used to control the enable of the OA module inside the SAC .
NMUXEN: This bit controls the enable of the negative input of OA . From the internal structure block diagram, we can see that there are two stages before the negative input of OA : the first stage is MUX , which is to select the input source, and the second stage is to enable MUX . That is to say, even if the input source of MUX is selected , this must be enabled, otherwise MUX and the negative input of OA will be disconnected.
NSEL: Negative input selection bit.
PMUXEN: This bit is similar to NMUXEN at the negative end , controlling the connection or disconnection between the positive end MUX and OA .
PSEL: Positive input selection bit.
GAIN: OA gain selection, which is the setting position of the adjustable gain in the figure described above. There are three bits, which can be used with NSEL, PSEL and MSEL to achieve gain selection in multiple modes.
MSEL: PGA mode selection, which controls the internal circuit structure as shown in the figure below:
In summary, we can find that the circuit topology, i.e., gain and other parameters are related to MSEL, PSEL, NSEL, GAIN . How to set these parameters? The figure below gives some examples of parameters. During use, you can set the registers according to the following information.
The SACxDAC register is obviously used to control the 12-bit DAC module inside the SAC . So what is the circuit structure of this internal DAC module?
Then we can easily understand the meaning of each bit in this register by looking at the internal structure diagram of the DAC .
DACSREF: This bit determines the reference voltage of the DAC . There are two options: primary and secondary . The reference source of each item can be found in the chip datasheet . The following figure shows the information of FR2355 .
DACLSEL: As can be seen from the above structure, this bit determines whether the set DAC value enters the DAC CORE . When the set data enters the DAC CORE , it will drive the corresponding voltage output. In other words, this bit determines the frequency of the DAC core voltage change, which can be real-time or pulse controlled.
DACDMAE: DAC internal DMA request enable. When the DAC data is updated, if this bit is enabled, there will be a DMA request.
DACIE: DAC interrupt enable signal, which can generate an interrupt signal to the CPU when the DAC data is updated .
DACEN: DAC enable bit.
This register is used to set the DAC voltage value. What is the DAC output voltage value? Calculate it according to the following formula:
This register is the status flag register of the DAC . Currently, only bit 0 is used for DACIFG , and the others are reserved.
DACIFG is the flag bit for updating DAC data.
DAC interrupt vector register, read-only register, is related to the interrupt generated by the DAC internal data update. When an interrupt occurs, the program at the interrupt vector will be triggered, and then the user's interrupt service program can be executed.
Well, after describing all the registers of SAC , here are some examples for your reference (MSP430FR2355) :
#include <msp430.h>
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
}
#include <msp430.h>
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
}
#include <msp430.h>
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
}
#include <msp430.h>
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: Output DAC data and use SAC as DAC
#include <msp430.h>
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 cascade mode:
#include <msp430.h>
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 cascade + comparator mode ( SAC can be directly connected to the internal comparator)
For a tutorial on how to use the comparator module, please refer to my other posts.
#include <msp430.h>
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 , here we have finished explaining all the contents of SAC . The basic commonly used program routines have also been provided. I will not explain the program in detail. When using the program, you can easily understand the configuration of the program by referring to the above register description.