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.
bcm2835PWMClockDivider
Especifica 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:
Se você deseja hardware PWM - você está preso ao pino 12 (BCM18), outros pinos GPIO usarão o software PWM.
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.
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.
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.
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%.
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) == 0
Embora os 12 valores válidos estejam listados acima.
A divisão da freqüência do relógio PWM pela freqüência de saída desejada fornece o valor da faixa de pulso.
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