aboutsummaryrefslogtreecommitdiffstats
path: root/examples/i2c-mcp4725-dac.cpp
blob: da9a34e953cb395d07002888e03e168f24f7e2f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// i2c-mcp4725-dac.cpp
//
// Written by Andrew Meyer <ajm@leaflabs.com>
// Modified by Marti Bolivar <mbolivar@leaflabs.com>
//
// Simple program showing how to control an MCP4725 DAC using the
// libmaple I2C interface. There's an MCP4725 breakout board available
// on SparkFun:
//
// http://www.sparkfun.com/products/8736
//
// How to use:
//
// 1. Connect the DAC SDA and SCL pins to I2C2, with a pullup
//    resistor (1 KOhm should work) to VCC.
// 2. Load the sketch and connect to SerialUSB.
// 3. Press the button.
//
// The program then makes sure the DAC is connected properly (during
// setup()), then has the DAC output a sawtooth wave (with loop()).

#include <wirish/wirish.h>
#include <libmaple/i2c.h>

#define MCP_ADDR         0x60
#define MCP_WRITE_DAC    0b01000000
#define MCP_WRITE_EEPROM 0b01100000
#define MCP_PD_NORMAL    0b00000000
#define MCP_PD_1K        0b00000010
#define MCP_PD_100K      0b00000100
#define MCP_PD_500K      0b00000110

static uint8 write_msg_data[3];
static i2c_msg write_msg;

static uint8 read_msg_data[5];
static i2c_msg read_msg;

/*
 * DAC control routines
 */

void mcp_i2c_setup(void) {
    write_msg.addr = MCP_ADDR;
    write_msg.flags = 0; // write, 7 bit address
    write_msg.length = sizeof(write_msg_data);
    write_msg.xferred = 0;
    write_msg.data = write_msg_data;

    read_msg.addr = MCP_ADDR;
    read_msg.flags = I2C_MSG_READ;
    read_msg.length = sizeof(read_msg_data);
    read_msg.xferred = 0;
    read_msg.data = read_msg_data;
}

void mcp_write_val(uint16 val) {
    write_msg_data[0] = MCP_WRITE_DAC | MCP_PD_NORMAL;
    uint16 tmp = val >> 4;
    write_msg_data[1] = tmp;
    tmp = (val << 4) & 0x00FF;
    write_msg_data[2] = tmp;

    i2c_master_xfer(I2C2, &write_msg, 1, 0);
}

uint16 mcp_read_val() {
    uint16 tmp = 0;

    i2c_master_xfer(I2C2, &read_msg, 1, 2);

    /* We don't care about the status and EEPROM bytes (0, 3, and 4). */
    tmp = (read_msg_data[1] << 4);
    tmp += (read_msg_data[2] >> 4);
    return tmp;
}

int mcp_test() {
    uint16 val;
    uint16 test_val = 0x0101;

    SerialUSB.println("Testing the MCP4725...");
    /* Read the value of the register (should be 0x0800 if factory fresh) */
    val = mcp_read_val();
    SerialUSB.print("DAC Register = 0x");
    SerialUSB.println(val, HEX);

    mcp_write_val(test_val);
    SerialUSB.print("Wrote 0x");
    SerialUSB.print(test_val, HEX);
    SerialUSB.println(" to the DAC");

    val = mcp_read_val();
    SerialUSB.print("DAC Register = 0x");
    SerialUSB.println(val, HEX);

    if (val != test_val) {
        SerialUSB.println("ERROR: MCP4725 not responding correctly");
        return 0;
    }

    SerialUSB.println("MCP4725 seems to be working");
    return 1;
}

/*
 * setup() and loop()
 */

void setup() {
    pinMode(BOARD_BUTTON_PIN, INPUT);
    i2c_master_enable(I2C2, 0);
    mcp_i2c_setup();

    waitForButtonPress();
    ASSERT(mcp_test());

    SerialUSB.println("Starting sawtooth wave");
}

void loop() {
    static uint16 dout = 0;

    mcp_write_val(dout);

    dout += 50;
    if (dout >= 32768) {
        dout = 0;
    }
}

// -- init() and main() -------------------------------------------------------

__attribute__((constructor)) void premain() {
    init();
}

int main(void) {
    setup();

    while (true) {
        loop();
    }
    return 0;
}