I2C / 静電容量式近接 & タッチセンサーAdafruit MPR121 / GPIOを使う / PWM波を生成する

pp.614ff.

なぜかデータシートに記述はないが、アプリケーションノートAN3894にはPWMがらみのレジスタが掲載されている。デューティの可変範囲は1/16~15/16、PWM周期は8 ms (=1 / (32 kHz / 256))である。下のプログラムは0/16~16/16の範囲でデューティが設定できるようにした。
f:id:ti-nspire:20200901085314p:plain:w600
↓これがデューティ1/16のとき(ソース出力。負荷は抵抗とLED):
f:id:ti-nspire:20200901085647p:plain:w500
↓これがデューティ15/16のとき(ソース出力。負荷は抵抗とLED):
f:id:ti-nspire:20200901085656p:plain:w500

f:id:ti-nspire:20200901064029p:plain:h315

 
    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);         // レジスタに書き戻す
    }
}