Tool/software:
Hello TI Community,
I'm currently working on a BLDC motor control project using the DRV8306. The motor has hall sensors for feedback.
However, I'm facing some issues:
-
The output waveform is distorted; it's not a clean trapezoidal shape.
-
The motor heats up after a short time of operation and emits a noticeable high-pitched whine.
I'm suspecting there might be a misconfiguration in either hardware or software.
I'll be attaching the following for your reference:
-
Code that handles the hall sensor reading and commutation logic
-
Schematic of the custom board connected to the DRV8306
- Osciloscope images of the output phases and hall sensor readings.
I have tried a different motor with the same specs, and the noise goes away on a proprietary board that came with the motor. On both the only signals I'm providing from the MCU is the PWM and Enable signal.
Unfortunately I only have a two-channel osciloscope, so I couldn't see all the hall sensors and phases on the same image. It would be highly appreciated if someone could enlighten me on some possible causes. Thanks in advance for your help!
Phase A and hall A:
Phase B and hall B:
Phase C and hall C
PWM Wave sent to the DRV:
Code:
#include <msp430.h> #include <stdbool.h> #include <stdint.h> #include <string.h> #define ACLK 32768 // Frequência do ACLK 32,768 KHz #define SMCLK 24000000 // Frequência do SMCLK 24 MHz const uint8_t tb_div[][3] = { {1, 0, 0}, {2, 0, 1}, {3, 0, 2}, {4, 0, 3}, {5, 0, 4}, {6, 0, 5}, {7, 0, 6}, {8, 0, 7}, {10, 1, 4}, {12, 1, 5}, {14, 1, 6}, {16, 1, 7}, {20, 2, 4}, {24, 2, 5}, {28, 2, 6}, {32, 2, 7}, {40, 3, 4}, {48, 3, 5}, {56, 3, 6}, {64, 3, 7}, {0, 0, 0}}; bool blower_init(uint16_t pwm_frq); void blower_set_dty (uint16_t dty); int main(void) { uint16_t flag = 0; uint16_t lng, dty = 5000,i=0; WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer // S01 - Inicializa��o do Sistema: Clocks e PMM WDTCTL = WDTPW | WDTHOLD; // P�ra o Watchdog Timer FRCTL0 = FRCTLPW | NWAITS_2; // Configura 2 wait state para FRAM, pois MCLK ser� configurado em 24 MHz P2SEL0 &= ~(BIT7 | BIT6); // Configura P2.6 como XOUT e P2.7 como XIN P2SEL1 |= (BIT7 | BIT6); // P2.6:P2SELx = 10b, P2.7:P2SELx = 10b do{ CSCTL7 &= ~(XT1OFFG | DCOFFG); // Limpa flags de falha de XT1 e DCO SFRIFG1 &= ~OFIFG; // Limpa flag de interrup��o por falha de oscilador }while (SFRIFG1 & OFIFG); // Aguarda at� a flag de falha de oscilador ser limpa __bis_SR_register(SCG0); // Desabilita FLL CSCTL3 |= SELREF__XT1CLK; // Define XT1 como refer�ncia de clock para FLL CSCTL0 = 0; // Inicializa CSCTL0.MOD = 00000b, pois o FLL ir� ajustar esses bits automaticamente // Inicializa CSCTL0.DCO = 000000000b, pois o FLL ir� selecionar o tap do DCO automaticamente CSCTL1 &= ~(DCORSEL_7); // Primeiramente faz CSTL1.DCOR_SEL = 000b CSCTL1 |= DCORSEL_7; // Seta CSCTL1.DCOR_SEL = 110b: DCO = 24 MHz CSCTL2 = FLLD_0 + 731; // Configura CSCTL2.FLLD = 000b, seleciona divisor do FLL loop como fdcoclock + 1 // Configura CSCTL2.FLLN = 731, desta forma a frequencia do DCO ser� REFO = 32.768 Hz x (731 + 1) = 23.986.176 Hz ~ 24 MHz __delay_cycles(3); // Espera 3 ciclos de clock __bic_SR_register(SCG0); // Habilita FLL while (CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1)); // Espera FLL locked que ocorre quando CSCTL7.FLLUNLOCK = 00b CSCTL4 = SELA__XT1CLK | SELMS__DCOCLKDIV; // Configura CSCTL4.SELA = 00b, escolhe XT1 como refer�ncia de clock para ACLK. Ent�o ACLK = 32.768 Hz // Configura CSCTL4.SELMS = 000b, escolhe DCO como refer�ncia de clock para MCLK e SMCLK PM5CTL0 &= ~LOCKLPM5; // Desabilita o estado default de alta imp�d�ncia dos pinos de GPIO no power-on // S02 - Define regi�o da FRAM sem prote��o SYSCFG0 = 0xA51F; // SYSCFG0.FRWPPW = 0xA5: // SYSCFG0.FRWPOA = 7: Seleciona 7 KB do in�cio da FRAM para DEV (1 KB) e DAT (6 KB) serem usados como RAM // SYSCFG0.DFWP = 1: // SYSCFG0.PFWP = 1 P1DIR = 0x00; // Configura P1DIR conforme coment�rio acima P1SEL0 = 0xFF; // Configura P1SEL0 conforme coment�rio acima P1SEL1 = 0xFF; // Configura P1SEL1 conforme coment�rio acima P1OUT = 0x00; // Configura P1OUT conforme coment�rio acima P1REN = 0x00; // Configura P1REN conforme coment�rio acima P2DIR = 0x3D; // Configura P2DIR conforme coment�rio acima P2SEL0 = 0x01; // Configura P2SEL0 conforme coment�rio acima P2SEL1 = 0xC0; // Configura P2SEL1 conforme coment�rio acima P2OUT = 0x00; // Configura P2OUT conforme coment�rio acima P2REN = 0x00; // Configura P2REN conforme coment�rio acima P3DIR = 0x11; // Configura P3DIR conforme coment�rio acima P3SEL0 = 0xEE; // Configura P3SEL0 conforme coment�rio acima P3SEL1 = 0xEE; // Configura P3SEL1 conforme coment�rio acima P3OUT = 0x00; // Configura P3OUT conforme coment�rio acima P3REN = 0x00; // Configura P3REN conforme coment�rio acima P4DIR = 0x01; // Configura P4DIR conforme coment�rio acima P4SEL0 = 0x0C; // Configura P4SEL0 conforme coment�rio acima P4SEL1 = 0x00; // Configura P4SEL1 conforme coment�rio acima P4OUT = 0x00; // Configura P4OUT conforme coment�rio acima P4REN = 0x00; // Configura P4REN conforme coment�rio acima P5DIR = 0x00; // Configura P5DIR conforme coment�rio acima P5SEL0 = 0x03; // Configura P5SEL0 conforme coment�rio acima P5SEL1 = 0x03; // Configura P5SEL1 conforme coment�rio acima P5OUT = 0x00; // Configura P5OUT conforme coment�rio acima P5REN = 0x00; // Configura P5REN conforme coment�rio acima P6DIR = 0x03; // Configura P6DIR conforme coment�rio acima P6SEL0 = 0x03; // Configura P6SEL0 conforme coment�rio acima P6SEL1 = 0x00; // Configura P6SEL1 conforme coment�rio acima P6OUT = 0x00; // Configura P6OUT conforme coment�rio acima P6REN = 0x00; // Configura P6REN conforme coment�rio acima PM5CTL0 &= ~LOCKLPM5; // Disable the GPIO power-on default high-impedance mode // to activate previously configured port settings TB0CCTL0 = 0x0010; // Habilita interrupção para CCR0 TB0CCR0 = 32768 - 1; // Define período de 32768 para que ocorra TB0CTL = 0x0110; // TBCLGRP = 00b: Cada TBxCLn é armazenado independentemente (sem agrupamento); // CNTL = 00b: Contador de 16 bits; // TBSSEL = 01b: Utiliza ACLK = 32768 Hz como clock source; // ID = 00b: Divide clock source por 1; // MC = 01b: Modo de contagem UP; // TBCLR = 0: Timer clear; // TBIE = 0: Habilita interrupção; // TBIFG = 0: Limpa interrupção pendente TB2CTL = 0x01E4; // TBCLGRP = 00b: Cada TBxCLn é armazenado independentemente (sem agrupamento); // CNTL = 00b: Contador de 16 bits; // TBSSEL = 01b: Utiliza ACLK = 32768 Hz como clock source; // ID = 11b: Divide clock source por 8, fazendo TB1CLK = ACLK / 8 = 4096Hz; // MC = 10b: Modo de contagem CONTINUOS_MODE; // TBCLR = 1: Timer clear; // TBIE = 0: Desabilita interrupção; // TBIFG = 0: Inrrelevante, pois não será utilizado interrupção para o timer TB2EX0 = 0x0003; // TBIDEX = 011b: Divide o clock de 4096 Hz do divisor ID, por 4, obtendo um clock de 1024 Hz. TB3CTL = 0x02E6; // TBCLGRP = 00b: Cada TBxCLn é armazenado independentemente (sem agrupamento); // CNTL = 00b: Contador de 16 bits; // TBSSEL = 10b: Utiliza SMCLK = 24 MHz como clock source; // ID = 11b: Divide clock source por 8; // MC = 10b: Modo de contagem Continuous; // TBCLR = 1: Timer clear; // TBIE = 1: Habilita interrupção; // TBIFG = 0: Limpa interrupção pendente TB3EX0 = 0x0002; // TBIDEX = 010b: Divide o clock de 3 MHz do divisor ID, por 3, obtendo um clock de 1 MHz. __enable_interrupt(); blower_init(3000); while(1){ blower_set_dty(dty); __delay_cycles(120000000); dty=0; } } /* * Fun��o que calcula a rota��o do motor para libera��o autom�tica * Par�metro de entrada: * uint16_t fgt_spd: velocidade de v�o, onde 1 = 0.1 Km/h * A fun��o retorna o valor de RPM que o motor deve girar para atender a taxa de aplica��o */ bool blower_init(uint16_t pwm_frq) { uint8_t i = 0; uint32_t hig, low; P2OUT |= BIT3; // Enable the blower control pin while (tb_div[i][0] != 0) { // Loop until the end of the tb_div table hig = SMCLK / tb_div[i][0]; // Calculate the highest frequency for the current divider low = hig / 65536; // Calculate the lowest frequency for the current divider if (pwm_frq >= low) { // Check if the desired PWM frequency is within range uint32_t aux = hig / pwm_frq; // Calculate the period count for the desired frequency // Configure TB1 TB1CCR0 = (uint16_t)aux; // Set the period TB1CCTL1 = OUTMOD_7; // Set output mode to Reset/Set TB1CCR1 = 0; // Initialize duty cycle to 0 TB1CTL = TBCLR | TBSSEL__SMCLK | MC__UP | tb_div[i][1]; // Configure TB1CTL directly // Configure TB3 TB3CCR0 = (uint16_t)aux; // Set the period TB3CCTL1 = OUTMOD_7; // Set output mode to Reset/Set TB3CCR1 = 0; // Initialize duty cycle to 0 TB3CTL = TBCLR | TBSSEL__SMCLK | MC__UP | tb_div[i][1]; // Configure TB3CTL directly // Configure TB1EX0 and TB3EX0 for extended divider TB1EX0 = tb_div[i][2]; TB3EX0 = tb_div[i][2]; return true; // Successfully configured } i++; // Move to the next divider in the table } return false; // Failed to configure } void blower_set_dty (uint16_t dty){ uint32_t aux; // Vari�vel auxiliar para determinar valor da contagem do per�odo if (dty > 0){ // Verifica se o duty � positivo if (dty > 10000){ // Se sim, verifica se o duty � maior que 100% dty = 10000; // Se for, limita em 100% } aux = dty; // Carrega o valor do duty aux *= TB1CCR0; // Multiplica pelo valor do per�odo aux /= 10000; // Divide o resultado por 100% TB1CCR1 = (uint16_t) aux; // Carrega o valor da contagem do per�odo aux = dty; // Carrega o valor do duty aux *= TB3CCR0; // Multiplica pelo valor do per�odo aux /= 10000; // Divide o resultado por 100% TB3CCR1 = (uint16_t) aux; // Carrega o valor da contagem do per�odo P4OUT |= BIT0; // Habilita o blower P3OUT &= ~BIT0; } else{ // Para o motor TB1CCR1 = 0; // Configura o duty cycle = 0 TB3CCR1 = 0; P4OUT &= ~BIT0; // Desabilita o blower P3OUT |= BIT0; // Desabilita o blower } }
Video of the noise:
Board Diagram: