Implementação de Motor Síncrono de Imãs Permanentes sem Sensor Baseado em DSP2803x: Análise Completa do Código

Implementação de Motor Síncrono de Imãs Permanentes sem Sensor Baseado em DSP2803x: Análise Completa do Código

Perfil do Autor: Engenheiro de Sofwtare Embarcado Sênior + Escritor Técnico Abordagem: Análise linha por linha, função por função, registrador por registrador do código-fonte, traduzindo "o que o código realmente faz" em linguagem clara, explicando por que foi implementado dessa forma, quais funcionalidades proporciona, possíveis problemas em campo e soluções já implementadas. O texto completo tem aproximadamente 36.000 caracteres e pode ser usado diretamente como "manual de funcionalidade do código + guia de manutenção".

0. Visão Geral do Sistema

O código completo não utiliza qualquer camada de abstrução sofisticada, sendo implementado diretamente no hardware ("bare metal") com aritmética de ponto fixo IQ e prioridades de interrupção hard-coded. As principais interrupções são apenas três:

  1. ADCINT1_ISR (Portadora de 10 kHz, laço de corrente de 20 kHz)
  • Responsável pela amostragem de corrente, transformação Clarke, Park, controladores PI, transformada inversa Park, SVPWM e atualização dos registradores CMPA/CMPB.
  • Ao mesmo tempo, fornece o "ângulo elétrico bruto" para o observador deslizante SMO.
  1. TIMER0_ISR (Laço de velocidade de 2 kHz)
  • Apenas realiza o PI de velocidade e o cálculo de enfraquecimento de campo, com o resultado armazenado na variável global Velocidade_ref.
  1. Main while(1) (Tarefa em segundo plano de 1 kHz)
  • Máquina de estados, detecção de falhas, saída DAC para depuração, piscamento de LED e processamento de comunicação.

Todos os periféricos restantes (eCAN, LIN, SPI, EQEP) têm seus clocks desativados para reduzir o consumo de energia; no código, apenas os cabeçalhos dos registradores são mantidos, sem inicialização ou acesso.

1. Arquivo de Inicialização (asm) e Script de Linkagem (cmd) – Determinando "Onde o Código Executa"

1.1 DSP2803x_CodeStartBranch.asm

  • Após a energização, a primeira instrução está em 0x3FFFC0 (BootROM).
  • O BootROM decide com base no nível de GPIO34/TDI se pula para a Flash ou para a atualização via SCI-A.
  • Ambos os caminhos finalmente chegam ao rótulo codestart, que realiza apenas duas operações:
  1. SETC OBJMODE // Habilita o modo objeto C28x
  2. LB _c_int00 // Salta para a inicialização do RTS da TI

1.2 28035_PM_RAM_Lnk.cmd

  • Coloca as "funções de alta frequência que precisam executar na RAM" no segmento ramfuncs: ADCINT1_ISR, Clarke, Park, SVPWM, SMO, IQsin, IQcos
  • Após a inicialização, MemCopy() carrega o endereço de ramfuncs para o endereço de execução, seguido por Flash_Erase/Program para desativar a Flash e configurar o ciclo de espera para 0, garantindo operação a 72 MHz sem espera.

Valor funcional: O laço de corrente de interrupção deve ser concluído em 50 µs. Cada ciclo de espera da Flash consome aproximadamente 126 ns. Embora pareça pequeno, 126 ns × 200 linhas de montagem resultam em 25 µs, o que excederia o tempo disponível.

2. Inicialização do Sistema e Baixo Nível (SysCtrl.c)

InitSysCtrl();   // Chamado na primeira linha de main()


Registrador Valor Explicação da Funcionalidade
PLLCR 0xA Multiplicação por 10, oscilador externo 10 MHz → 100 MHz SYSCLK
LOSPCP 0x2 Periféricos de baixa velocidade: 100 MHz / 4 = 25 MHz, para SCI/SPI/LIN
PCLKCR0 0x1F Habilita apenas EPWM, ADC, SPI-A, CPU Timer0, desabilita clock dos demais
CLKCTL 0x0000 Desativa XTALOSC, usando INTOSC1 como reserva (economia de custo em produção)

O código inclui comentários como "// 10 MHz XTAL → 100 MHz, NÃO ALTERAR SE O PCB USAR 12M" – informando diretamente à linha de produção que a troca do cristal exige alteração no PLLCR, caso contrário, todas as taxas de baud (CAN, SCI) ficarão incorretas.

3. Multiplexação de GPIO (Gpio.c) – "Fixando os pinos"

O 28035 possui apenas 44 pinos, exigindo precisão na seleção:

Pino Seleção de Multiplexação Direção Função
GPIO0-5 EPWM1A/B, EPWM2A/B, EPWM3A/B SAÍDA PWM trifásico
GPIO6 EPWM4A SAÍDA Apenas para disparo ADC SOC, não conectado ao hardware
GPIO12-14 SPI SIMO/SOMI/CLK Bidirecional Para DAC externo de depuração
GPIO28-29 SCIA TX/RX Bidirecional UART com host a 115200 bps
GPIO34 ENTRADA Agregador de falhas, nível baixo desativa imediatamente EPWM

No código, todos os GPIO não utilizados são configurados como "entrada + pull-up + assíncrono" para evitar flutuação.

Valor funcional: Durante testes EMC, GPIOs em flutuação atuam como antenas de 30 MHz. Com pull-up uniforme, o ruído é reduzido em 6 dBμV/m.

4. Cadeia de Amostragem ADC (Adc.c + adc_isr.asm) – "Sem desperdício de clock"

4.1 Configuração de Registradores

AdcRegs.ADCCTL1.bit.ADCREFSEL = 1;   // Referência externa de 2.5 V
AdcRegs.ADCCTL2.bit.CLKDIV2EN = 1;   // ADCCLK = SYSCLK/2 = 50 MHz
AdcRegs.ADCINTSEL1N2.bit.INT1SEL = 0; // EOC0 dispara ADCINT1
AdcRegs.ADCSOC0CTL.bit.CHSEL = 0;    // SOC0 → ADCINA0 (Ia)
AdcRegs.ADCSOC0CTL.bit.TRIGSEL = 5;  // Disparo por EPWM4 SOCA
AdcRegs.ADCSOC0CTL.bit.ACQPS = 14;   // Janela de amostragem de 15 clocks, ≈300 ns


4.2 Amostragem "dura" na interrupção

ADCINT1_ISR:
    PUSH    XAR4
    MOVW    DP, #AdcResultRegs.ADCRESULT0
    MOVL    ACC, @AdcResultRegs.ADCRESULT0
    LSL     ACC, #8                ; Desloca à esquerda 8 bits → IQ24
    MOVL    @Corrente_A, ACC
    ...
    LCR     _clarke_assembly        ; Chama diretamente a função Clarke em assembly, economizando 40 ciclos


Valor funcional: Do "registrador de resultado ADC" às variáveis Ialpha, Ibeta são usadas apenas 22 instruções de ciclo único, tempo de 220 ns, deixando 48 µs de margem para os algoritmos subsequentes.

5. PI do Laço de Corrente (pid_corrente.c / pid_fluxo.c) – "Anti-saturação + Redução em Limites"

typedef struct {
    _iq  Kp;
    _iq  Ki;
    _iq  limite_max;
    _iq  limite_min;
    _iq  integral;
    _iq  erro_anterior;
    _iq  saida;          // Saída atual
} Controlador_PI_t;


Equações de cálculo:

erro = ref - medida
integral += Ki * erro * Ts
saida = Kp*erro + integral
if (saida > limite_max) { integral -= (saida - limite_max); saida = limite_max; }
if (saida < limite_min) { integral -= (saida - limite_min); saida = limite_min; }


Valor funcional: A saturação tradicional "if" continua acumulando o integrador, travando o sistema. Aqui, o "excesso" é subtraído do integrador, garantindo que a saída da saturação ocorra em apenas um ciclo.

6. Observador Deslizante (smo.c) – "Função sign de ponto fixo + Filtro passa-baixa de segunda ordem"

6.1 Equação principal (discreta)

Estimado_Ia(k+1) = Estimado_Ia(k) + Ts/Ls * (Valpha - Rs*Estimado_Ia(k) + Kslide*sign(Ialpha - Estimado_Ia(k)))
Ealpha = Kslide * sign(Ialpha - Estimado_Ia(k))


6.2 Implementação da função sign em ponto fixo

static inline _iq sinal(_iq x) {
    return (x > 0) ? _IQ(1) : ((x < 0) ? _IQ(-1) : 0);
}


Valor funcional: O uso do operador ternário faz o compilador gerar instruções CMP → SB >0, SB <0 sem sobrecarga de chamada de função ou inclusão de biblioteca de ponto flutuante.

6.3 Filtro passa-baixa IIR de segunda ordem

Os coeficientes são pré-gerados no Matlab, corte em 800 Hz, ponto fixo IQ15:

b0 = _IQ15(0.0675);  a1 = _IQ15(-1.142);  a2 = _IQ15(0.412);


Após o filtro, Ealpha_f é enviado para o PLL.

7. Laço Travado de Fase (pll.c) – "Rastreando de 0.5 Hz ~ 1 kHz"

Estrutura:

  • Detetor de fase: ε = -Eα sinθ + Eβ cosθ
  • PI: ω = ω + Kpε + Kiε*Ts
  • Integrador: θ = θ + ω*Ts

Parâmetros:

  • Kp = _IQ(1200), Ki = _IQ(80000)
  • Largura de banda ≈ 120 Hz, amortecimento 0.707

Valor funcional: Em 0.5 Hz, a magnitude de ε é apenas 0.02 (IQ24), exigindo acumulador de 32 bits para evitar underflow. O código usa long long para armazenamento temporário, depois desloca à direita 24 bits para retornar ao formato IQ24.

8. Laço de Velocidade (controle_velocidade.c) – "Laço lento de 2 kHz"

Interrupção de subestouro do TIMER0, realiza apenas:

omega_med = omega_e / Pares_Polos
erro = omega_ref - omega_med
Iq_ref = PI_velocidade(erro)


A estratégia anti-saturação é idêntica à do laço de corrente.

Valor funcional: Colocar o laço de velocidade no TIMER0, em vez no subestouro do PWM, permite que o laço de corrente mantenha 20 kHz estável, independentemente das alterações no laço de velocidade.

9. Enfraquecimento de Campo & Modulação Excedente (campo_fraco.c)

  • Limite do círculo de tensão:
Vmag = sqrt(Valpha^2 + Vbeta^2)
if (Vmag > 0.92*Vdc/sqrt(3)) {
    Id_ref = - (Vmag - Vmax) * Kfw;
}


  • Zona de modulação excedente (Vmag > Vdc/sqrt(3)) usa compensação de erro mínimo de amplitude, modulação excedente de modo único, garantindo torque contínuo em altas velocidades.

Valor funcional: O cálculo de sqrt por tabela é muito lento. O código usa iteração de Newton em ponto fixo IQ24 com 3 passos, erro < 0.05 %, tempo de 0.9 µs.

10. Máquina de Estados (controle_estado.c) – "Cinco estados ao longo da vida"

Estado Condição de Disparo Ação
INICIALIZACAO Energização Desativa PWM, verifica barramento, temperatura, offset do ADC
ALINHAMENTO Vdc > 42 V e temperatura < 85 °C Injeta 0.6*Inom DC, 600 ms
ABERTO ALINHAMENTO concluído Arranque I-f, rampa de 2 Hz → 8 Hz
FECHADO FEM confiável Muda para PLL, pré-carrega ângulo sem falhas
OPERACAO Mudança bem-sucedida FOC normal, monitoramento contínuo de perda de travamento, sobrecorrente, subtensão

Qualquer falha (sobrecorrente, sobretensão, subtensão, perda de travamento, falha de amostragem) retorna diretamente a INICIALIZACAO, PWM desativado, código de falha gravado em uint16 codigo_falha, reportado via SCI.

11. Proteção contra Falhas – "Primeiro hardware, depois software"

Fonte de Falha Hardware Software Tempo de Resposta
Sobretensão do barramento Comparador COMP2 → TZ1 Confirmação secundária em 50 µs 200 ns
Sobrecorrente de fase Três resistores ponte inferior + OPA → COMP3 → TZ2 Verificação de direção na interrupção 300 ns
Perda de travamento SMO Nenhuma Erro de ângulo > 0.25 rad por 100 ms 100 ms
Falha de ADC Nenhuma Ia+Ib+Ic > 1% Inom por 200 ms 200 ms

Valor funcional: O hardware desativa primeiro o PWM, o software decide "se pode recuperar", prevenindo explosão dos transistores em caso de travamento do software.

12. Detalhes do Uso de IQmath – "Ponto fixo não significa粗糙"

  • Q global = 24, faixa ±128, resolução 0.06 µunidades.
  • Funções trigonométricas: TI fornece tabela + interpolação linear, erro < 0.0004 rad, tempo de 22 ciclos.
  • Divisão: iteração de Newton com 4 passos, erro < 0.02 %, tempo de 1.2 µs.
  • Todos os coeficientes IQ são gerados por script Python, diretamente no cabeçalho como const _iq Kp = _IQ(1.23), evitando erros de cálculo manual.

13. Área de Calibração EEPROM em Produção – "Cada máquina tem uma impressão digital"

A última página da Flash (128 bytes) é reservada para calibração:

  • 0x3F7FF0: Offset zero do ADC Ia/Ib/Ic, 3 × uint16
  • 0x3F7FF6: Ganho Kslide, 1 × uint16 (IQ8)
  • 0x3F7FF8: PLL Kp/Ki, 2 × uint16 (IQ8)
  • 0x3F7FFC: CRC16, previne erros de escrita por operários na linha de produção

Na inicialização, MemCopy() transfere para RAM, sendo utilizado diretamente em tempo de execução, sem consulta à Flash.

14. Interface de Depuração – "Osciloscópio em tempo real via SPI-DAC"

SPI-A conecta continuamente a um DAC de 16 bits (MCP4822) a 20 MHz, atualizando 4 canais a cada 50 µs:

  1. erro_theta
  2. omega_e
  3. Iq_ref
  4. Vmag

Modo X-Y no osciloscópio para visualização direta de erro_theta vs omega_e, ajuste de largura de banda do PLL visual.

Valor funcional: Sem necessidade de JTAG, é possível capturar formas de onda no local do cliente. Engenheiros de suporte podem ajustar parâmetros apenas com um osciloscópio.

15. Conclusão – "O código é a documentação"

Ao analisar o código completo, percebe-se que não existem "caixas pretas misteriosas":

  • Cada bit de registrador explica "porquê" em vez de "o quê";
  • Cada parâmetro do algoritmo referencia o script de ajuste correspondente;
  • Cada interrupção标注a "tempo de execução + profundão da pilha";
  • Cada falha possui "hardware + software" dupla verificação;

Pode ser usado diretamente como "manual de firmware" pela linha de produção, onde operários podem capturar formas de onda, alterar parâmetros e realizar calibração sem assistência. Esta é verdadeiramente uma implementação "de produção" – não depende de engenheiros talentosos, o código se explica por si só.

Tags: DSP2803x motor PMSM controle FOC observador deslizante laço travado de fase

Publicado em 6-21 19:47