Caro leitor, neste artigo abordarei as características e configurações básicas do conversor ΔΣ (Delta-Sigma) de 16 bits (SD16_A) presente em diversos microcontroladores da família MSP430 da Texas Instruments, com foco especial no modelo MSP430F2013.
Para o desenvolvimento da minha dissertação de mestrado acabei precisando pesquisar sobre conversores ADC e AFE’s (Analog Front End) com mais resolução que os usuais 10-bit presente na maioria dos microcontroladores. Nesta procura um colega indicou o modelo MSP430F2013 que tinha uma característica bastante importante para mim, era compatível com a Launchpad G2, ou seja, eu poderia tomar proveito do SD16_A utilizando uma launchpad como base de testes, o que foi excelente. Fica aqui a dica, se você tiver uma launchpad G2 é possível trocar o uC e brincar com o SD16_A.
Características do SD16_A
- Arquitetura ΣΔ de 16-bit de segunda ordem;
- Entradas diferenciais ou single-ended (referenciadas ao GND);
- Referência interna de 1,2 V;
- Entrada para referência externa (selecionável por software);
- Sensor de temperatura interno;
- Modulador operando a até 1,1 MHz;
- Modo low power.
A estrutura geral do SD16_A pode ser vista na figura a seguir:
O conversor Delta-Sigma
Existem diversos tipos de conversores ADC, sendo o SAR (sucessivas aproximações) o mais comum na maioria dos uC’s bem como dos conversores de uso padrão. Além do SAR podemos listar os tipos Flash, Pipeline, Single-Slope, Dual-Slope (e Multi-slope) e Delta-Sigma.
Cada conversor possui uma característica específica, geralmente ponderando entre frequência de amostragem e resolução, onde a escolha de modelo ideal dependerá das características da aplicação foco.
Os conversores delta-sigma são bastante populares nas aplicações de instrumentação de precisão devido a sua excelente resolução e custo, já que são mais baratos e simples de serem implementados quando comparados a um conversor dual-slope, como os tradicionalmente utilizados em multímetros de bancada de precisão. A estrutura básica de um conversor delta-sigma é apresentada na figura a seguir.
São conhecidos como conversores 1-bit já que sua saída é um trem de pulsos (1/0) em alta frequência, também conhecida como PDM (pulse density modulation). Esse trem de pulsos passa por um filtro digital, geralmente um filtro Sync3 ou WideBand, e por fim por um decimador que irá diminuir a quantidade de bits para um tamanho mais eficiente, conforme pode ser visto na figura a seguir.
Quanto maior for o oversampling utilizado, tradicionalmente apresentado como OSR (oversampling ratio) nos datasheets, maior será o número de bits úteis do conversor e consequentemente a resolução obtida.
A animação a seguir apresenta o efeito do oversampling aplicado diretamente na saída do modulador, demonstrando o efeito de reconstrução do sinal. Deixo aqui a indicação de leitura do artigo no Hackaday além de assistirem ao vídeo.

SD16_A do MSP430F2013
O MSP430F2013 é um microcontrolador com foco no baixo consumo baseado em uma arquitetura RISC de 16-bit, podendo operar a até 16 MHz. A quantidade de memória RAM e Flash disponível pode se tornar um desafio dependendo da aplicação, com valores de 128 Bytes e 2 KB, respectivamente.
O SD16_A deste modelo possui 4 canais analógicos (externos) multiplexados, podendo operar na configuração single-ended ou diferencial. O pinout deste uC é apresentado a seguir.
O ADC possui uma tensão de referência interna de 1,2 V, entretanto, pode-se utilizar uma referência externa caso necessário.
A tensão máxima (VFSR)suportada na entrada de cada canal depende tanto da tensão de referência como do ganho configurado no PGA (programmable gain amplifier) interno. Considerando a referência interna com ganho 1x no PGA, a tensão máxima possível é de ±0,6 V.
Os principais registradores para configuração do SD16_A são: SD16CTL, SD16CCTL0, SD16INCTL0 e SD16AE.
SD16CTL
Dentre os principais bits podemos destacar:
- SD16REFON: habilitar a referência interna de 1,2 V;
- SD16SSELx: seleção da fonte de clock;
- SD16DIVx: divisor do clock;
- SD16XDIVx: segundo divisor de clock.
SD16CCTL0
Dentre os principais bits podemos destacar:
- SD16SC: bit utilizado para iniciar a conversão (e paralisar no modo contínuo);
- SD16IE: habilita a interrupção;
- SD16DF: seleciona o formato de saída da conversão. Offset (positivo) ou complemento de dois (2’s);
- SD16OSRx e SD16XOSR: controlam a taxa de oversampling;
- SD16SNGL: conversão simples ou contínua;
- SD16UNI: modo unipolar (single-ended) ou diferencial.
SD16INCTL0
Dentre os principais bits podemos destacar:
- SD16INCHx: seleciona qual o canal a ser utilizado;
- SD16GAINx: controla o ganho do PGA interno, de 1x a 32x;
- SD16INTDLYx: geração de interrupção após quantas conversões.
SD16AE
- realiza a conexão do canal com o pino externo.
SD16MEM0
Além disso, utilizamos o registrador SD16MEM0 para ler o resultado das conversões após a interrupção, ou após a verificação do flag via pooling.
As configurações completas devem ser verificadas no Users Guide da família MSP430x2xx.
A seguir irei apresentar dois exemplos, um com conversões contínuas na configuração de entrada single-ended, o outro com conversão simples no modo diferencial disparado pela chave S2 da Launchpad. Os exemplos foram desenvolvidos com a IDE Code Composer Studio v8.
Exemplo 1
No primeiro exemplo o SD16_A é configurado para realizar conversões contínuas no modo single-ended utilizando o canal 1 (P1.2 em referência ao GND interno). No loop é dado início na conversão pelo ADC e então a CPU é colocada no modo Low Power Mode 0 (LPM0), sendo acordada/requisitada a cada interrupção gerada pelo conversor ADC. Com todas as amostras salvas a o ADC é paralisado e a CPU volta ao modo normal, finalizando o processamento necessário para então reiniciar o processo.
Cada conversão gera uma interrupção que é tratada em seu respectivo vetor. As amostras são salvas em um array com 32 posições ao mesmo tempo em que cada amostra é acumulada (somada). Ao final do processo calculamos a média das amostras e convertermos o valor para a respectiva tensão na entrada do ADC (float). Como o total de amostras é compatível com a base 2, podemos realizar a divisão através do rotacionamento da variável para direita, neste caso rotacionando 5 vezes para direita.
Os resultados devem ser avaliados através do debuger.
/******************************************************************************
* SD16_A continuous conversion - single-ended
* Based on MSP430ware example
* - MSP430F20x3 Demo - SD16A, Sample A1+ Continuously, Set P1.0 if > 0.3V
******************************************************************************
*
* MSP430F20x3
* ------------------
* /|\| XIN|-
* | | |
* --|RST XOUT|-
* | |
* Vin+ -->|A1+ P1.2 |
* |A1- = VSS P1.0|-->LED
* | |
*
* Haroldo Amaral - 2019
* www.github.com/agaelema
******************************************************************************/
#include <msp430.h>
#include <stdint.h>
/******************************************************************************
* Definitions and macros
******************************************************************************/
#define ADC_GAIN (1) // pga gain
#define VREF (double)(1.2) // reference voltage
#define VFSR (double)((VREF/2.0)/ADC_GAIN) // full scale range
#define ADC_BITS ((1UL << 16) - 1) // 2^16-1 - unipolar max count
#define ADC_VBIT (float)(VFSR/ADC_BITS) // voltage per bit
/******************************************************************************
* Variables
******************************************************************************/
uint16_t array[32]; // array to save ADC readings
uint8_t counter = 0; // conversion counter
uint32_t temp = 0; // temporary variable
uint16_t average = 0; // average value
float Vadc = 0; // input adc voltage
/******************************************************************************
* main code
******************************************************************************/
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
BCSCTL1 = CALBC1_1MHZ; // Internal clock calibration
DCOCTL = CALDCO_1MHZ; // Internal clock calibration
P1DIR |= BIT0; // Set P1.0 to output direction
/******************************************************************************
* SD16_A configuration
******************************************************************************/
/* 1.2V ref, SMCLK, div 1x, div 1x */
SD16CTL = SD16REFON | SD16SSEL_1 | SD16DIV_0 | SD16XDIV_0;
/* interrupt enable, 1024 OSR, continuous conv, unipolar (single ended) */
SD16CCTL0 = SD16IE | SD16OSR_1024 | SD16UNI;
/* A1 +, gain 1x, interrupt after fourth sample */
SD16INCTL0 = SD16INCH_1 | SD16GAIN_1 | SD16INTDLY_0;
/* P1.2 A1+, A1- = VSS */
SD16AE = SD16AE2;
while(1)
{
SD16CCTL0 |= SD16SC; // start conversion - continuous conversion
__no_operation(); // DEBUGER BREAKPOINT
_BIS_SR(LPM0_bits + GIE); // go to low power mode 0
temp = temp >> 5; // do the average
average = (uint16_t)temp;
Vadc = average * ADC_VBIT; // convert to voltage
/* reset variables auxiliary variables */
counter = 0;
temp = 0;
}
}
#pragma vector = SD16_VECTOR
__interrupt void SD16ISR(void)
{
// save and accumulate sample N samples
if ( counter < (1<<5) ) // 32 samples array
{
array[counter] = SD16MEM0; // save the sample
counter++;
temp += SD16MEM0; // accumulate
}
else
{
SD16CCTL0 &= ~SD16IFG; // clear interruption flag
SD16CCTL0 &= ~SD16SC; // stop conversion
LPM0_EXIT;
}
}
A seguir temos o resultado das conversões quando atingimos um breakpoint colocado em “__no_operation()”. é possível verificar o valor da tensão presente na entrada single-ended, a média das 32 amostras e também os valores do array, plotados no gráfico à direita.
Exemplo 2
No segundo exemplo o SD16_A é configurado para realizar conversões simples no modo diferencial utilizando o canal 2 (V+ em P1.4, V- em P1.5). A CPU é mantida no modo Low Power Mode 0 (LPM0), sendo acordada/requisitada a cada interrupção gerada pelo GPIO P1.3 (conectado a chave S2 da launchpad) e pelo conversor ADC.
Cada vez que a chave S2 é pressionada é gerada uma interrupção que dará início à conversão do SD16_A. Ao final da conversão uma nova interrupção é gerada, sendo tratada em seu respectivo vetor.
O resultado da conversão é convertido na tensão presente na entrada diferencial, caso o valor for maior ou igual que zero o LED1 (P1.0) é setado, caso contrário é resetado, fornecendo um feedback sobre a tensão na entrada.
Neste exemplo é possível uma interação direta sem a necessidade de avaliar os resultados no debugger.
/******************************************************************************
* SD16_A single conversion - differential
* - triggered by switch S2 of launchpad (P1.3)
******************************************************************************
*
* MSP430F20x3
* ------------------
* /|\| XIN|-
* | | |
* --|RST XOUT|-
* | |
* Vin+ -->|A2+ P1.4 |
* Vin- -->|A2- P1.5 P1.0|-->LED
* | |
*
* Haroldo Amaral - 2019
* www.github.com/agaelema
******************************************************************************/
#include <msp430.h>
#include <stdint.h>
/******************************************************************************
* Definitions and macros
******************************************************************************/
#define ADC_GAIN (1) // pga gain
#define VREF (double)(1.2) // reference voltage
#define VFSR (double)((VREF/2.0)/ADC_GAIN) // full scale range
#define ADC_BITS ((1UL << 15) - 1) // 2^15-1 - bipolar max count - one bit to signal
#define ADC_VBIT (float)(VFSR/ADC_BITS) // voltage per bit
/******************************************************************************
* Variables
******************************************************************************/
int16_t temp = 0; // temporary variable
float Vadc = 0; // input adc voltage
/******************************************************************************
* main code
******************************************************************************/
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
BCSCTL1 = CALBC1_1MHZ; // internal clock calibration
DCOCTL = CALDCO_1MHZ; // internal clock calibration
P1DIR |= BIT0; // P1.0 as output
P1OUT &= ~BIT0; // reset output
P1REN |= BIT3; // enable internal resistor
P1OUT |= BIT3; // configure resistor as pullup
P1IE |= BIT3; // enable pin interruption
P1IES |= BIT3; // falling edge - high>low
P1IFG &= ~BIT3; // clear flag
/******************************************************************************
* SD16_A configuration
******************************************************************************/
/* 1.2V ref, SMCLK, div 1x, div 1x */
SD16CTL = SD16REFON | SD16SSEL_1 | SD16DIV_0 | SD16XDIV_0;
/* interrupt enable, 2's format, 1024 OSR, single conv, differential; */
SD16CCTL0 = SD16IE | SD16DF | SD16OSR_1024 | SD16SNGL;
/* A1 +, gain 1x, interrupt after fourth sample */
SD16INCTL0 = SD16INCH_2 | SD16GAIN_1 | SD16INTDLY_0;
/* A1+ = P1.2, A1- = P1.3 */
SD16AE = SD16AE4 | SD16AE5;
_BIS_SR(LPM0_bits + GIE); // go to low power mode 0
}
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
P1IFG &= ~BIT3; // clear flag
SD16CCTL0 |= SD16SC; // Set bit to start conversion
}
#pragma vector = SD16_VECTOR
__interrupt void SD16ISR(void)
{
temp = SD16MEM0; // save SD16 sample
Vadc = temp * ADC_VBIT; // convert to voltage
if (Vadc >= 0)
{
P1OUT |= BIT0;
}
else
{
P1OUT &= ~BIT0;
}
__no_operation();
}
Conclusão
Com estes dois exemplos se tornará mais simples a utilização deste periférico presente em diversos microcontroladores da linha MSP430.
No próximo artigo irei apresentar uma abordagem mais prática, unindo o SD16_A com a comunicação I2C, tornando o MSP430F2013 em um conversor ADC de 16-bit externo com funções programáveis.
Referências
Tearing Into Delta Sigma ADC’s.
Delta-sigma ADC basics: Understanding the delta-sigma modulator.









Anexo
Prezado Dr.Haroldo Amaral, boa tarde! Gostei bastante do seu artigo, parabéns! Possuo a Placa MSP430G2xxx e consegui o MSP430F2013 no intuito de replicar os testes e laboratórios. Suas orientações são bem ilustrativas e me ajudam a melhor compreender esse mundo dos conversores DAC/ADC. Gostaria no entanto de, se possível, solicitá-lo a informação de qual aplicativo/ferramenta foi usada para plotar o gráfico com os valores das saídas do exemplo 1 do artigo acima. Estou aguardando chegar a placa com o conversor ADS1115, para continuar o meu aprendizado com o seu segundo trabalho postado. Mais uma vez, parabéns e sucesso na sua… Leia mais »
Prezado Alfonsoff, fico feliz que tenha gostado do artigo e esteja replicando.
Os gráficos desta primeira parte foram gerador dentro do Code Composer Studio (CCS), a IDE da TI utilizada para o MSP430. Dentro do debugger você pode manda plotar o conteúdo de uma array, no caso o array com as 32 amostras do SD16.
Na segunda parte do artigo os gráficos foram gerados no Excel basicamente copiando e colando o conteúdo do Serial Monitor do Arduino IDE, mas poderia ser diretamente plotado no Serial Plotter do Arduino IDE.
Fico aguardando o resultado dos seus testes.
Att,
Prezado Prof. Haroldo, muito boa tarde! Consegui plotar o gráfico referente a saída do conversor para o exemplo 1, conforme sua explicação acima. Gostei do trabalho e dos resultados. Aproveito para deixar também os resultados do exemplo 2. Fiz uma pequena alteração para o valor do “if” para a saída Vadc. Uma vez que não entrei no pinos P1.4 e P1.5 com uma tensão simétrica (V+ 0 V-) nas entradas diferenciais. Coloquei P1.4 (+V variável) e P1.5 (GND) e, dado que o ganho do PGA está setado em 1x, coloquei a condição de verificação para a saída de tensão e… Leia mais »
Prezado @Alfonsoff , fico feliz em saber que os resultados foram bons e fico aguardando os resultados comparando com o ADS1115.