稼働中

Raspberry Pi Pico(d_09)MCP4725 DAコンバータ

MCP4725 HW-315 (I2C)

MCP4725は分解能12bitのD/Aコンバータです。I2C通信で制御します。Raspberry Pi PicoでMCP4725搭載のHW-315モジュールを使ってみました。
I2Cの周波数は標準100kHz、Fast400kHz、High-Speed3.4MHzとあります。標準の100kHzで動作を確認しました。
※micro:bitの記事e_54からRaspberry Pi Picoで使えるように追記、修正等をしました。

外観

MCP4725モジュールHW-315の外観写真です。(以後はMCP4725と記載します。)
MCP4725外観

接続例

MCP4725の電源電圧は2.7V~5.5VなのでRaspberry Pi Picoと接続できます。その際のD/A変換出力は3.3Vが最大になります。
I2C通信にはI2C1のSDA(GP10)SCL(GP11)を使いました。
D/A変換出力をRaspberry Pi Picoで測定するために、MCP4725の出力端子からRaspberry Pi PicoのADC2(GP28)に接続しています。
接続図
接続出来たらI2Cデバイスのスレーブアドレスを調べてみます。
ThonnyのShellで確認しました。
MCP4725のスレーブアドレスは以下のように96(0x60)でした。


>>> from machine import I2C,Pin
>>> i2c=I2C(1, scl=Pin(11), sda=Pin(10), freq=100_000)
>>> i2c.scan()
[96]            #0x60

MCP4725の説明

データシートから抜粋してMCP4725の説明します。※詳細はMCP4725のデーターシートを参照ください。
(#印の行は下方のスクリプトに対応する部分です。adrはMCP4725のアドレスです。)

POWER-DOWN
POWER-DOWNモードがあります。レジスタのPD1、PD0ビット値でモード変更できます。
D/A変換する時はNormalMode(0、0)です。他は各抵抗値が負荷になる省電力状態です。
POWER-DOWN
※MCP4725のデータシートから抜粋

Read
MCP4725の読込みは下図のようになっています。
I2CでReadすると2nd~6th byteの5bytesのデータが返ります。
# r_dat=i2c.readfrom(adr,5)

2nd byteにはEEPROM Write Status POR(Power-On-Reset)とPOWER-DOWN MODEのデータがあります。
# by2_rdpo=r_digit(r_dat[0])[0:2] (RDY/BSY POR)
# by2_pd10=r_digit(r_dat[0])[5:7] (PD1 PD0)

3rd byteの8bitと4th byte+上位4bitの12bitがDACデータになります。
# by3_da=r_digit(r_dat[1])
# by4_da=r_digit(r_dat[2])[0:4]
# reg_dat=’0b’+by3_da + by4_da (DAC Resister 12bit Data)
MCP4725_Read
※MCP4725のデータシートから抜粋

Write
MCP4725の書込みは下図のようになっています。
書込むデータをbuf=bytearray(3)として、
i2c.writeto(adr,buf)
で書込みます。
繰返しての書込みは2nd-4byteを繰返します。
例えばbuf=bytearray(3の倍数)として、相当のデータを与えて書込みます。
MCP4725_Write
※MCP4725のデータシートから抜粋
2nd byte(buf[0])のC2,C1,C0の値によって、レジスタだけに書込む(0,1,0)、EEPROMにも書込む(0,1,1)を設定できます。まだPD1、PD0でPower のモードが設定できます。通常(0,0)で出力します。(0,1)なら1.0kΩ、(1,0)なら100kΩ、(1,1)なら500kΩで接地します。待機電力が軽減されるようです。
#buf[0]=int(‘0b’+ cmd +’00’+pd +’0’)
buf[0]

出力させたい電圧値を12bitデータに変換した値に変換します。
#w_dat=w_digt(s_dat)

変換した値の上位8bitを3rd byte(buf[1])に、
#buf[1]=int(‘0b’+ w_dat[0:8])

下4bitを4th byte(buf[2])の上位4bitに設定します。
#buf[2]=int(‘0b’+ w_dat[8:12]) << 4
4th byte

スクリプト

MCP4725のスクリプトは以下のようにしました。
※開発環境はThonnyです。ThonnyでMicroPythonをRaspberry Pi Pico with RP2040にインストールして使っています。


pico_mcp4725_test_01b.py
#!/usr/bin/env python
# -*- coding: utf-8 -*
from machine import I2C,Pin,ADC
import time
# MCP4725 12-Bit Digital-to-Analog Converter with EEPROM Memory
i2c = I2C(1, scl=Pin(11), sda=Pin(10), freq=100_000)

adr=0x60  # slave address hex(96)='0x60'
VDD=3300  #3300mV

def r_digit(dat):   # int
    dat=bin(dat)    # str  
    value='0'*(8-len(dat[2:])) + dat[2:] # str
    return value

def read_DAC():
    # read 5bytes
    r_dat=i2c.readfrom(adr,5)
    # 2 byte r_dat[0]
    by2_rdpo=r_digit(r_dat[0])[0:2] #RDY/BSY POR   str
    by2_pd10=r_digit(r_dat[0])[5:7] #PD1 PD0       str
    print('<2 byte>')
    print('|RDY/BSY|POR|=',by2_rdpo, '|PD1|PD0|=', by2_pd10)

    # 3 byte r_dat[1] 4nd byte r_dat[2]
    by3_da=r_digit(r_dat[1])
    by4_da=r_digit(r_dat[2])[0:4]
    reg_dat='0b'+by3_da + by4_da    # DAC Resister 12bit Data str

    print('<3-4 byte 12bit>')
    print('Register_Data=', reg_dat,hex(int(reg_dat)) )

    # 5 byte r_dat[3] 6nd byte r_dat[4] EEPROM Data
    by5_pd10=r_digit(r_dat[3])[1:3]  #PD1 PD0 
    by5_da=r_digit(r_dat[3])[4:8]
    by6_da=r_digit(r_dat[4])
    rom_dat='0b'+by5_da + by6_da    # DAC EEPROM 12bit Data str

    print('<5-6 byte PD, 12bit>')
    print('|PD1|PD0|=', by5_pd10)
    print('EEPROM_Data=', rom_dat, hex(int(rom_dat)))
    return #r_dat

def w_digt(dat):   # int
    dat=bin(dat)   # str
    value='0'*(12-len(dat[2:])) + dat[2:] # str '0'埋12文字
    return value

def write_DAC(value,cmd='010', pd='00'):
    # write cmd '010' DAC-Regi '011'DAC-Regi+EEPROM
    # 設定できるのは4095/4096*VDD まで hex(4095)'0xfff'
    s_dat=int(value/VDD*4096)
    
    #print('value=',value,'s_dat(0d,0x)=',s_dat, hex(s_dat))
    print('set mv =',value)
    
    w_dat=w_digt(s_dat) #str
    #print('w_dat=',w_dat)
    buf=bytearray(3) # I2C write data
    buf[0]=int('0b'+ cmd +'00'+pd +'0')  # command PowerDown
    # DAC no Data wo 8bit 4bit ni bunkai site set suru
    buf[1]=int('0b'+ w_dat[0:8])         # D11-D4 8bit
    buf[2]=int('0b'+ w_dat[8:12]) << 4   # D3-D0 4bit 4 shift-up
    
    #print('write_buf_data=',buf)
    
    i2c.writeto(adr,buf)
        #EEPROM Write Time typ 25msec max 50msec
        if cmd=='011':
        time.sleep_ms(50)
    return buf

## example
# MCP4725 Write Data    出力値等の設定
write_DAC(VDD/2,cmd='010', pd='00')

# MCP4725 OUT DataをADC2で測定
adc=ADC(Pin(28))
val=adc.read_u16()*(VDD/2**16)
print('Vout mv=',val)
print('')

# MCP4725 Read Data      データの読出し
read_DAC()

関数
(1)write_DAC(value,cmd=’010′, pd=’00’)
出力電圧等を設定します。
value:アナログ出力電圧値(mV)
cmd:書込むモード(’010’ならレジスタだけ、’011’ならEEPROMと両方
pd:パワーダウンモードを設定します。
(2)read_DAC()
レジスタ、EEPROMのデータ読出します。

実行結果

OutputをVDD/2(1650mV)で実行してみました。
write_DAC(VDD/2,cmd=’010′, pd=’00’)
結果は以下のようになりました。※Thonnyのshellに表示されます。


>>> %Run -c $EDITOR_CONTENT
set mv = 1650.0             # 設定値 3300/2 mv
Vout mv= 1660.071           # ADCで読んだ値 だいたい合ってる。

<2 byte>                            # EEPROM Status,Current Setting DAC
|RDY/BSY|POR|= 11 |PD1|PD0|= 00     # PDはD/Aモード
<3-4 byte 12bit>
Register_Data= 0b100000000000 0x800 # 12bitの値
<5-6 byte PD, 12bit>                # EEPROM Data
|PD1|PD0|= 00                       # PDはD/Aモード
EEPROM_Data= 0b100000000000 0x800   # 12bitの値(初期は0.5*VDD)
>>> 

次に、OutputをVDD/3(1100mV)にして見ました。
write_DAC(VDD/3,cmd=’010′, pd=’00’)


set mv = 1100.0
Vout mv= 1108.04

<2 byte>
|RDY/BSY|POR|= 11 |PD1|PD0|= 00
<3-4 byte 12bit>
Register_Data= 0b010101010101 0x555     # VDD/3値の12bitデータに
<5-6 byte PD, 12bit>
|PD1|PD0|= 00
EEPROM_Data= 0b100000000000 0x800       # cmd='010'なのでEEPROM値は無変化

EEPROMにもデータ書込む、パワーダウンを設定して実行してみます。
write_DAC(VDD/3,cmd=’011′, pd=’01’)


>>> %Run -c $EDITOR_CONTENT
set mv = 1100.0
Vout mv= 9.667969                       # パワーダウン状態(1kΩ)

<2 byte>
|RDY/BSY|POR|= 11 |PD1|PD0|= 01
<3-4 byte 12bit>
Register_Data= 0b010101010101 0x555     # VDD/3値の12bitデータに
<5-6 byte PD, 12bit>
|PD1|PD0|= 01
EEPROM_Data= 0b010101010101 0x555       # EEPROMにも12bitデータ書込み
>>> 

まとめ

Raspberry Pi PicoでMCP4725を使ってD/A変換ができました。