Página 1 de 2

STM32F ADC/PWM 12 bits

MensagemEnviado: 11 Mar 2021 15:42
por vtrx
Alguém pode tira uma dúvida minha?
O ADC do STM32f103 é de 12 bits,isso ocupa dois bytes,o PWM é de 16 bits,dois bytes.
Analisando alguns códigos na Net encontrei;
Result = (ADC_GetConversionValue(ADC1)>>2);
,segundo consta o deslocamento é para usar 10 bits.
Se eu utilizar uma saida PWM diretamente para reproduzir a entrada ananlógica(TIM2->CCR1 = Result;),o 'audio' é reproduzido,mas se eu utilizar diretamente a variável Result com o resultado da conversão,o audio não é reproduzido,tenho que dividir por 2,3 etc.
Se o PWM usa um registrador de 16 bits e o ADC retorna um valor de 12 bits,porque não reproduz diretamente,tipo Result = (ADC_GetConversionValue(ADC1)); ?
Alguem pode me explicar?

Re: STM32F ADC/PWM 12 bits

MensagemEnviado: 11 Mar 2021 17:18
por eletroinf
"o pwm é de 16 bits"

Isso depende. Tu configura quantos bits é quando define o módulo do contador. Qual é o valor de seu módulo do contador?

Re: STM32F ADC/PWM 12 bits

MensagemEnviado: 11 Mar 2021 17:32
por vtrx
Código: Selecionar todos
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    // Timer freq = timer_clock / ((TIM_Prescaler+1) * (TIM_Period+1))
    // Timer freq = 72MHz / ((1+1) * (1023+1) = 35.15kHz
    TIM_TimeBaseInitStruct.TIM_Prescaler = 1;
//    TIM_TimeBaseInitStruct.TIM_Period = 1023;
    TIM_TimeBaseInitStruct.TIM_Period = 800;//44khz   
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);
    TIM_Cmd(TIM2, ENABLE);

    // Step 2: Initialize PWM
    TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStruct.TIM_Pulse = 0;
    TIM_OC1Init(TIM2, &TIM_OCInitStruct);
    TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);

    // Step 3: Initialize TIM3 for timer interrupt
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    // Timer freq = timer_clock / ((TIM_Prescaler+1) * (TIM_Period+1))
    // Timer freq = 72MHz / ((1+1) * (1023+1) = 35.15kHz
    TIM_TimeBaseInitStruct.TIM_Prescaler = 1;
    TIM_TimeBaseInitStruct.TIM_Period = 800;//44.100
//    TIM_TimeBaseInitStruct.TIM_Period = 407;//88.200khz
//    TIM_TimeBaseInitStruct.TIM_Period = 1601;//22.050khz
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
    // Enable TIM3 interrupt
    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
    TIM_Cmd(TIM3, ENABLE);

Re: STM32F ADC/PWM 12 bits

MensagemEnviado: 11 Mar 2021 19:10
por eletroinf
Nesse caso
Código: Selecionar todos
TIM_TimeBaseInitStruct.TIM_Period = 800;

O seu limite de configuração de pwm é 800.
Então a configuração do duty cycle deve estar entre 0 e 800. Veja que nem chega a 10 bit.

Re: STM32F ADC/PWM 12 bits

MensagemEnviado: 11 Mar 2021 19:48
por vtrx
Então se for aumentar o período a frequência PWM vai baixar obrigatoriamente se quiser aumentar a resolução?

Re: STM32F ADC/PWM 12 bits

MensagemEnviado: 11 Mar 2021 20:02
por eletroinf
Exatamente.

Re: STM32F ADC/PWM 12 bits

MensagemEnviado: 11 Mar 2021 20:07
por vtrx
Neste caso a solução seria um DAC dedicado?
E se o processador tivesse um clock maior?

Re: STM32F ADC/PWM 12 bits

MensagemEnviado: 11 Mar 2021 20:24
por eletroinf
Funciona assim.
Tu tem o clock que alimenta o timer, geralmente é o clock da CPU podendo ser dividido pelo prescale (que pode ser configurado 1:1).
Vamos supor que tu esteja com o stm32f103 com a CPU @ 72 MHz.
Bom, vamos supor que tu queira uma resolução de 12 bit no PWM.
Bom 2^12 são 4096. Isto é, para ir de 0 a 4095 (que são 4096 steps) alimentado por 72 MHz, tu vai ter um sinal de saída de:
72 MHz/4096 = 17578,125 Hz
Entendido até aqui? Cada bit de resolução é obtido por uma contagem de pulso do clock que alimenta o Timer.
Agora, se tu quer uma frequência fixa que tu escolheu e a partir daí quer obter o valor do registrador de Período, é só mudar as variáveis da mesma conta.
Supondo que tu queiras 44 kHz de saída no PWM a partir dos 72 MHz:
Periodo = 72 MHz/44 kHz = 1636,36 -> 1636 (11 bits mas não ocupando todo o valor possível, que seria 2048)

Então basta configurar o prescale 1:1, e o período do timer (registrador de reload) em 1636.
O contador do PWM inicia em zero, com o pino pwm em zero; Quando a contagem atinge o valor definido no registrador comparador, o pino de pwm de saída vai para nível 1 e a contagem continua até chegar no valor de período, no caso 1636, situação em que o contador volta a zero e o pino de saída é zerado, recomeçando o processo.

Expliquei de forma sucinta e de cabeça, não olhei exatamente os nomes dos registradores e os detalhes, mas funciona assim.
Pode ver que se aumentar o clock da CPU aumenta a resolução de saída, em bits, para a mesma frequência do pwm.

Espero que ajude.
Abraço

Re: STM32F ADC/PWM 12 bits

MensagemEnviado: 12 Mar 2021 15:53
por vtrx
Legal sua explicação.
Baseado nela,'melhorei' a resolução do seguinte modo;
1-TIM_Prescaler = 0 e TIM_TimeBaseInitStruct.TIM_Period = 2047;
2-Inicializei outro timer para(ADC),TIM_Prescaler = 0;e TIM_Period = 2047;
No momento não estou no laboratório para medir,mas esta funcionando como esperado,usando o valor do ADC dividido por 2(ADC_GetConversionValue(ADC1)>>1)

Re: STM32F ADC/PWM 12 bits

MensagemEnviado: 14 Mar 2021 10:01
por vtrx
Não encontrei referencia se o ADC setup deste micro tem a opção de 8 bits de resolução no ADC.
Ele é de 12 bits,vou ter que deslocar bits para reduzir para 8?

Re: STM32F ADC/PWM 12 bits

MensagemEnviado: 23 Mar 2021 23:07
por vtrx
Gastando tempo aqui um pouco,com um STM que tem DAC,o 'pipoco' de fundo sumiu...
Não sei se é por causa do DAC ou é pela frequência de 168mhz.
O problema agora é acertar o circuito de entrada pois esta distorcendo com volume de entrada a 100%(PC),tenho que reduzir a 50%.
Chiado ainda fica se aumentar muito o volume na saída sem sinal,mas pelo menos os estalos sumiram.
Minha opinião rápida aqui é que entre uma saída PWM ou DAC,pelo menos para áudio,não vi vantagem no DAC interno do micro,a não ser usar os 12 bits de resolução.

Re: STM32F ADC/PWM 12 bits

MensagemEnviado: 24 Mar 2021 08:06
por KrafT
Parabéns pela aula, Eletroinf. Confesso que fiquei muito feliz em ver conteúdo no AMS51 e não apenas propaganda de links para uma página concorrente.

Re: STM32F ADC/PWM 12 bits

MensagemEnviado: 24 Mar 2021 09:25
por eletroinf
Pelo jeito que tu descreveu esse pipoco me faz acreditar que é um detalhe na configuração do PWM. Teria de ver com o osciloscópio ou salvar os valores do duty e visualizar.

Pra usar somente 8 bit, faz um RRF quando lê o valor do ADC, e tá resolvido, algo tipo:

valor_8_bit = ADC_RES >>4;

considerando ADC_RES como sendo o registrador com o resultado da conversão AD, de 12 bit.

Re: STM32F ADC/PWM 12 bits

MensagemEnviado: 24 Mar 2021 18:40
por vtrx
eletroinf escreveu:Pelo jeito que tu descreveu esse pipoco me faz acreditar que é um detalhe na configuração do PWM. Teria de ver com o osciloscópio ou salvar os valores do duty e visualizar.

Pra usar somente 8 bit, faz um RRF quando lê o valor do ADC, e tá resolvido, algo tipo:

valor_8_bit = ADC_RES >>4;

considerando ADC_RES como sendo o registrador com o resultado da conversão AD, de 12 bit.

Brigadão de novo.
Fiz o upgrade do circuito,com o STM32F407,reescrevi os códigos e agora esta razoável,ADC/DAC 12bits com resultado satisfatório a 44.100khz.
No primeiro teste,usei como entrada(ADC)um pino que era compartilhado com um hardware da placa,por isso o som baixo e distorcido se eu aumentasse o sinal,vindo do PC,isso não acontecia com o outro hardware(STM32F103),tive que baixar o manual do kit e procurar o diagrama para saber como usar todos os pinos e verificar qual é compartilhado.

Re: STM32F ADC/PWM 12 bits

MensagemEnviado: 26 Mar 2021 14:19
por Guri
eletroinf escreveu:Funciona assim.
Tu tem o clock que alimenta o timer, geralmente é o clock da CPU podendo ser dividido pelo prescale (que pode ser configurado 1:1).
Vamos supor que tu esteja com o stm32f103 com a CPU @ 72 MHz.
Bom, vamos supor que tu queira uma resolução de 12 bit no PWM.
Bom 2^12 são 4096. Isto é, para ir de 0 a 4095 (que são 4096 steps) alimentado por 72 MHz, tu vai ter um sinal de saída de:
72 MHz/4096 = 17578,125 Hz
Entendido até aqui? Cada bit de resolução é obtido por uma contagem de pulso do clock que alimenta o Timer.
Agora, se tu quer uma frequência fixa que tu escolheu e a partir daí quer obter o valor do registrador de Período, é só mudar as variáveis da mesma conta.
Supondo que tu queiras 44 kHz de saída no PWM a partir dos 72 MHz:
Periodo = 72 MHz/44 kHz = 1636,36 -> 1636 (11 bits mas não ocupando todo o valor possível, que seria 2048)

Então basta configurar o prescale 1:1, e o período do timer (registrador de reload) em 1636.
O contador do PWM inicia em zero, com o pino pwm em zero; Quando a contagem atinge o valor definido no registrador comparador, o pino de pwm de saída vai para nível 1 e a contagem continua até chegar no valor de período, no caso 1636, situação em que o contador volta a zero e o pino de saída é zerado, recomeçando o processo.

Expliquei de forma sucinta e de cabeça, não olhei exatamente os nomes dos registradores e os detalhes, mas funciona assim.
Pode ver que se aumentar o clock da CPU aumenta a resolução de saída, em bits, para a mesma frequência do pwm.

Espero que ajude.
Abraço


Que aula...parabéns Eletroinf :roll: