pp.614ff.
なぜかデータシートに記述はないが、アプリケーションノートAN3894にはPWMがらみのレジスタが掲載されている。デューティの可変範囲は1/16~15/16、PWM周期は8 ms (=1 / (32 kHz / 256))である。下のプログラムは0/16~16/16の範囲でデューティが設定できるようにした。
↓これがデューティ1/16のとき(ソース出力。負荷は抵抗とLED):
↓これがデューティ15/16のとき(ソース出力。負荷は抵抗とLED):
pad.enable_gpio(0b00000011); // led[1:0] (ele[5:4])をGPIOにする。 pad.set_gpio_direction(0b00000011); // led[1:0] (ele[5:4])のIOをOUTにする。 pad.set_gpio_circuit(0, SOURCE); // led_0 (ele_4)の出力回路をソース(ハイサイドオープンドレイン)にする。 pad.set_gpio_circuit(1, SOURCE); // led_1 (ele_5)の出力回路をソース(ハイサイドオープンドレイン)にする。 /* pad.analog_write(0, 15); // led_0 (ele_4)からデューティ15/16のPWM波を出力する。 pad.analog_write(1, 1); // led_1 (ele_4)からデューティ1/16のPWM波を出力する。 while(1); /*/ // led_1,0 (ele_5,4)からPWM波を出力する。ぼわーっとLEDを明滅させる。 while(1){ for(int i=0; i<=16; i++){ pad.analog_write(0, i); // (ledのピン番号, duty=16分のいくつ) pad.analog_write(1, i); _delay_ms(30); } for(int i=16; i>=0; i--){ pad.analog_write(0, i); pad.analog_write(1, i); _delay_ms(30); } } //*/
void MPR121Class::analog_write(uint8_t led_n, uint8_t duty){ uint8_t data_reg = i2c.read(_SLA, GPIO_DATA); // 一旦GPIOデータレジスタを読み出して、 if(!duty){ // 指定されたdutyが16分の0の場合は、 data_reg &= ~(1 << led_n); // 目的のデータレジスタビットをとにかく0にして、 i2c.write(_SLA, GPIO_DATA, data_reg); // レジスタに書き戻して、PWMをオフにする。 } else if(duty<16){ // dutyが16分の1~15の場合は、 data_reg |= (1 << led_n); // 目的のデータレジスタビットをとにかく1にして、 i2c.write(_SLA, GPIO_DATA, data_reg); // レジスタに書き戻して、PWMをオンにする。 } else{ // dutyが16分の16の場合は、 data_reg |= (1 << led_n); // 目的のデータレジスタビットをとにかく1にして、 i2c.write(_SLA, GPIO_DATA, data_reg); // レジスタに書き戻して duty = 0; // 常時点灯にする。 } uint8_t pwm_reg = i2c.read(_SLA, PWM_0 + led_n/2); // 一旦目的のPWMレジスタを読み出して、 if(led_n%2==0){ // ledピン番号が偶数の場合は pwm_reg = (pwm_reg & 0xF0) | (duty & 0x0F); // 下4ビットを消して目的のdutyに書き換えて、 i2c.write(_SLA, PWM_0 + led_n/2, pwm_reg); // レジスタに書き戻す } else if(led_n%2==1){ // ledピン番号が奇数の場合は pwm_reg = (pwm_reg & 0x0F) | ((duty & 0x0F) << 4); // 上4ビットを消して目的のdutyに書き換えて、 i2c.write(_SLA, PWM_0 + led_n/2, pwm_reg); // レジスタに書き戻す } }