Conduzindo a freqüência de saída PWM

8

Depois de muitas horas de pesquisa e leitura infrutíferas, eu ainda não tinha um entendimento completo de como e por que emitir frequências específicas do pino PWM de hardware no RPi sem usar a 'caixa preta' de outra pessoa.

Parece haver um pouco de informações imprecisas ou incompletas sobre os detalhes, bem como os vários termos usados ​​- 'divisor de relógio', 'ciclo de serviço', 'intervalo PWM' e os dados PWM em si, e como todos eles se relacionam juntos para produzir uma frequência específica - no meu caso, para direcionar frequências de áudio específicas para fora de um sonorizador piezo.

Neil
fonte

Respostas:

14

Finalmente, entendi (ish) o arquivo de cabeçalho do driver bcm2835.h, por isso pensei em postar e responder minha própria pergunta para outras pessoas.

Os bits relevantes do cabeçalho:

PWM

O BCM2835 suporta PWM de hardware em um subconjunto limitado de pinos GPIO. Esta biblioteca bcm2835 fornece funções para configurar e controlar a saída PWM nesses pinos.

O BCM2835 contém 2 canais PWM independentes (0 e 1), cada um dos quais conectado a um subconjunto limitado de pinos GPIO. Os seguintes pinos GPIO podem ser conectados aos seguintes canais PWM:

  GPIO PIN    RPi pin  PWM Channel    ALT FUN
  12                    0             0
  13                    1             0
  18          1-12      0             5
  19                    1             5
  40                    0             0
  41                    1             0
  45                    1             0
  52                    0             1
  53                    1             1

Para que um pino GPIO emita a saída de seu canal PWM, ele deve ser definido para a Função Alt fornecida acima. Observe com cuidado que as versões atuais do Raspberry Pi apenas expõem um desses pinos (GPIO 18 = RPi Pin 1-12) nos cabeçalhos de E / S e, portanto, esse é o único pino de E / S no RPi que pode ser usado para PWM. Além disso, deve ser definido como ALT FUN 5 para obter saída PWM.

Ambos os canais PWM são acionados pelo mesmo relógio PWM, cujo dvider do relógio pode ser variado usando bcm2835_pwm_set_clock(). Cada canal pode ser ativado separadamente com bcm2835_pwm_set_mode(). A saída média do canal PWM é determinada pela razão DATA / RANGE para esse canal. Use bcm2835_pwm_set_range()para definir o intervalo e bcm2835_pwm_set_data()os dados nessa proporção

Cada canal PWM pode ser executado nos modos Balanceado ou Mark-Space. No modo Balanceado, o hardware envia uma combinação de pulsos de clock que resulta em pulsos de dados gerais por pulsos de RANGE. No modo Mark-Space, o hardware define a saída HIGH para pulsos de clock DATA de largura, seguida por LOW para pulsos de clock RANGE-DATA.

O relógio PWM pode ser ajustado para controlar as larguras de pulso PWM. O relógio PWM é derivado de um relógio de 19,2 MHz. Você pode definir qualquer divisor, mas alguns comuns são fornecidos pelobcm2835PWMClockDivider

Por exemplo, suponha que você queira acionar um motor DC com PWM em cerca de 1kHz e controlar a velocidade em incrementos de 1/1024, de 0/1024 (parado) a 1024/1024 (completo). Nesse caso, você pode definir o divisor do relógio para 16 e o ​​RANGE para 1024. A frequência de repetição do pulso será 1,2 MHz / 1024 = 1171,875 Hz.

bcm2835PWMClockDividerEspecifica o divisor usado para gerar o relógio PWM a partir do relógio do sistema. As figuras abaixo mostram o divisor, o período do relógio e a frequência do relógio. O relógio dividido é baseado na taxa de clock base PWM nominal de 19.2MHz. As frequências mostradas para cada divisor foram confirmadas por medição

typedef enum
{
    BCM2835_PWM_CLOCK_DIVIDER_2048  = 2048,    /*!< 2048 = 9.375kHz */
    BCM2835_PWM_CLOCK_DIVIDER_1024  = 1024,    /*!< 1024 = 18.75kHz */
    BCM2835_PWM_CLOCK_DIVIDER_512   = 512,     /*!< 512 = 37.5kHz */
    BCM2835_PWM_CLOCK_DIVIDER_256   = 256,     /*!< 256 = 75kHz */
    BCM2835_PWM_CLOCK_DIVIDER_128   = 128,     /*!< 128 = 150kHz */
    BCM2835_PWM_CLOCK_DIVIDER_64    = 64,      /*!< 64 = 300kHz */
    BCM2835_PWM_CLOCK_DIVIDER_32    = 32,      /*!< 32 = 600.0kHz */
    BCM2835_PWM_CLOCK_DIVIDER_16    = 16,      /*!< 16 = 1.2MHz */
    BCM2835_PWM_CLOCK_DIVIDER_8     = 8,       /*!< 8 = 2.4MHz */
    BCM2835_PWM_CLOCK_DIVIDER_4     = 4,       /*!< 4 = 4.8MHz */
    BCM2835_PWM_CLOCK_DIVIDER_2     = 2,       /*!< 2 = 9.6MHz, fastest you can get */
    BCM2835_PWM_CLOCK_DIVIDER_1     = 1        /*!< 1 = 4.6875kHz, same as divider 4096 */
} bcm2835PWMClockDivider;

Em suma:

  1. Se você deseja hardware PWM - você está preso ao pino 12 (BCM18), outros pinos GPIO usarão o software PWM.

  2. Você provavelmente precisará definir o modo PWM para o modo 'Mark-Space' para a maioria dos casos de uso e razões de sanidade, conforme descrito acima.

  3. Nesse modo, a duração de cada 'pulso' é ALTO vs BAIXO é determinada pela razão entre os dados PWM e a faixa PWM - independentemente da velocidade do relógio PWM.

  4. A faixa PWM é efetivamente a 'resolução' ou o número de possíveis 'divisões' de cada pulso. Quanto mais divisões, maior a resolução e, portanto, mais estados codificáveis ​​para uma determinada largura de pulso.

  5. O 'ciclo de serviço' é a razão entre os dados do PWM e o intervalo do PWM, expressa em porcentagem. Uma faixa PWM de 10 com dados PWM de 8 é um ciclo de trabalho de 80%.

  6. A velocidade do relógio PWM é uma potência de dois divisores. Portanto, a velocidade do relógio escolhida para o PWM deve ser divisor & (divisor -1) == 0Embora os 12 valores válidos estejam listados acima.

  7. A divisão da freqüência do relógio PWM pela freqüência de saída desejada fornece o valor da faixa de pulso.

  8. Como codificava o áudio e usava um piezo, eu precisava de um ciclo de trabalho de 50% para maximizar a oscilação piezo e, portanto, o volume. Portanto, o valor dos dados PWM é sempre metade do valor da faixa PWM - 50% ALTO 50% BAIXO.

Para calcular a frequência necessária, escolha um divisor de relógio que faça sentido para a sua aplicação - escolhi 16, o que equivale a 1,2 MHz. Assim:

A nota de A é 440Hz, F # é 370Hz, C # é 277Hz

PWMClock = 16; // 1.2Mhz

const A4_RANGE = 1.2e6 / 440;  // 1.2Mhz/440Hz
A4Data = A4_RANGE / 2;

const F4S_RANGE = 1.2e6 / 370;  // 1.2Mhz/370Hz
F4SData = F4S_RANGE / 2;

const C4S_RANGE = 1.2e6 / 277;  // 1.2Mhz/277Hz
C4SData = C4S_RANGE / 2;

Você pode facilmente mudar o intervalo do PWM para cima e para baixo em oitavas - o intervalo * 2 diminui uma oitava, o intervalo * 0,5 diminui uma.

Se você deseja acionar um servo a, digamos, 50Hz, o mesmo cálculo de faixa é válido:

PWM Range = PWM frequency / Desired Output Frequency

(O valor máximo do intervalo PWM, de acordo com algumas postagens, é de 4096 - na minha experiência, isso não é verdade, pois a execução de um C # como acima fornece um intervalo PWM de 4332, que funciona conforme o esperado.)

Como a maioria das coisas - é fácil quando você sabe como.

~ N

Neil
fonte
3
Observe que o bit "somente 12 pinos" se aplica aos modelos de 26 pinos. Os modelos de 40 pinos possuem mais três (13, 18 e 19), mas ainda existem apenas 2 canais de clock e os pinos têm uma associação conectada com um ou outro (os pinos 12 e 18 são os canais 0, 13 e 19 são canais 1); conforme os documentos citados acima, libbcm2835 permitirá que você configure ambos os canais e todos os quatro pinos. As funções ALT para fazer isso diferem para cada pino; aqui há uma tabela, em grande parte retirada diretamente da folha de dados do Broadcom SoC. As entradas riscadas são apenas nos modelos de 40 pinos.
goldilocks
7

Nos Pis recentes (aqueles com o cabeçalho de expansão de 40 pinos e o módulo de computação), o GPIO 12/13/18/19 pode ser usado para fornecer sinais PWM de hardware.

A fonte do relógio PWM não precisa ser o cristal de 19,2 MHz , o pigpio usa o PLLD de 500 MHz.

Para um método simples de linha de comando para definir uma frequência PWM de hardware, consulte http://abyz.me.uk/rpi/pigpio/pigs.html#HP

joan
fonte