AVRly - AVR Development Resources
mcp48x2_dac.h File Reference

Driver for the MCP4812 10 bit DAC (digital to analog converter) chip. More...

#include <stdbool.h>
#include <stdint.h>

Go to the source code of this file.

Classes

struct  dac_channel_t
 Struct for config values for each channel - this is only to be used as a nested struct within the dac_config_t struct. More...
 
struct  dac_config_t
 Config struct for DAC. More...
 

Macros

#define DAC_CHANNEL_A   true
 
#define DAC_CHANNEL_B   false
 

Enumerations

enum  model_num_t { mcp4802 , mcp4812 , mcp4822 }
 Enumerated constants to select the DAC model number. More...
 

Functions

void init_dac (dac_config_t *p_config)
 Initialisation routine (run once at startup). More...
 
void dac_set_voltage (bool channel_a, uint16_t millivolts)
 Sends a new millivolts value to be output on DAC (Along with config settings). More...
 
void dac_set_voltage_12_bit (bool channel_a, uint16_t millivolts, bool fractional)
 Sends a new millivolts value to be output on DAC (Along with config settings). More...
 
void dac_reconfigure (void)
 Applies new config settings. More...
 
void pulse_latch (void)
 Pulses LDAC pin low for a brief time (1uS). More...
 

Detailed Description

Driver for the MCP4812 10 bit DAC (digital to analog converter) chip.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Author
Jason Duffy
Date
4th March 2022

This file provides the basic low-level functionality for the MCP4812 10 bit DAC from Microchip. This driver currently only allows for a single DAC to be used, but this might be improved on at a later date. This driver was written using the datasheet for the Microchip MCP4812 chip, which can be found at the link below.

See also
https://ww1.microchip.com/downloads/en/DeviceDoc/20002249B.pdf

Definition in file mcp48x2_dac.h.

Macro Definition Documentation

◆ DAC_CHANNEL_A

#define DAC_CHANNEL_A   true

Definition at line 44 of file mcp48x2_dac.h.

◆ DAC_CHANNEL_B

#define DAC_CHANNEL_B   false

Definition at line 45 of file mcp48x2_dac.h.

Enumeration Type Documentation

◆ model_num_t

Enumerated constants to select the DAC model number.

Definition at line 51 of file mcp48x2_dac.h.

52{
53 mcp4802,
54 mcp4812,
55 mcp4822
model_num_t
Enumerated constants to select the DAC model number.
Definition: mcp48x2_dac.h:52

Function Documentation

◆ init_dac()

void init_dac ( dac_config_t p_config)

Initialisation routine (run once at startup).

This function is to be called before using any other DAC functions. Instantiate the dac_config_t object first then pass it's address into and call init_lcd() before using any other lcd functions.

Parameters
p_configis a pointer to the dac_config_t object.

Definition at line 89 of file mcp48x2_dac.c.

90{
91 // Copy config object pointer to a variable with file scope.
92 p_config_global = p_config;
93
94 // Delay to allow power ramp up in device.
95 _delay_ms(500);
96
97 // Initialise SPI comms.
98 init_spi(lsb_first,
99 controller,
100 rising_edge,
101 sample_leading_edge,
102 cpu_clk_div_16,
103 single_speed);
104
105 DAC_CTRL_DDR |= (1 << DAC_CS); // Set chip select as output.
106 DAC_CTRL_PORT |= (1 << DAC_CS); // Set CS line high (not selected).
107 DAC_CTRL_DDR |= (1 << LDAC); // Set LDAC line (latch) as output.
108 DAC_CTRL_PORT |= (1 << LDAC); // Set LDAC high.
109
110 // Save the value to bitshift millivolts value by.
111 if (p_config_global->model == mcp4802)
112 {
113 mv_resolution_shift = EIGHT_BIT_MV_OFFSET;
114 level_resolution_shift = EIGHT_BIT_LEVEL_OFFSET;
115 }
116 else if (p_config_global->model == mcp4812)
117 {
118 mv_resolution_shift = TEN_BIT_MV_OFFSET;
119 level_resolution_shift = TEN_BIT_LEVEL_OFFSET;
120 }
121 else
122 {
123 mv_resolution_shift = TWELVE_BIT_MV_OFFSET;
124 level_resolution_shift = TWELVE_BIT_LEVEL_OFFSET;
125 }
126
127 // Establish latching settings
128 if (!p_config_global->sync_manually)
129 {
130 DAC_CTRL_PORT &= ~(1 << LDAC);
131 }
132
133 // Send new values to DAC
135}
void init_spi(spi_transfer_mode_t transfer_mode, spi_control_mode_t control_mode, spi_polarity_mode_t polarity_mode, spi_phase_mode_t phase_mode, spi_clk_rate_t clk_rate, spi_dbl_clk_mode_t dbl_clock)
Initialisation routine to set up SPI comms.
Definition: atmega_spi.c:53
void dac_reconfigure(void)
Applies new config settings.
Definition: mcp48x2_dac.c:240

◆ dac_set_voltage()

void dac_set_voltage ( bool  channel_a,
uint16_t  millivolts 
)

Sends a new millivolts value to be output on DAC (Along with config settings).

For 8 or 10 bit models only.

Parameters
channel_atrue = Channel A, false = Channel B.
millivoltsmV value to be output by DAC. Ensure that this value doesn't exceed the maxixum for the DAC model and gain setting.

Definition at line 145 of file mcp48x2_dac.c.

146{
147 // Manipulate mv value to suit register size of chip and gain setting.
148 if (channel_a)
149 {
150 if (p_config_global->channel_a.gain_low)
151 {
152 p_config_global->channel_a.level =
153 (millivolts >> mv_resolution_shift);
154 }
155 else
156 {
157 p_config_global->channel_a.level =
158 (millivolts >> (mv_resolution_shift + 1));
159 }
160 }
161 else
162 {
163 if (p_config_global->channel_b.gain_low)
164 {
165 p_config_global->channel_b.level =
166 (millivolts >> mv_resolution_shift);
167 }
168 else
169 {
170 p_config_global->channel_b.level =
171 (millivolts >> (mv_resolution_shift + 1));
172 }
173 }
174
175 // Send new values to DAC
177}

◆ dac_set_voltage_12_bit()

void dac_set_voltage_12_bit ( bool  channel_a,
uint16_t  millivolts,
bool  fractional 
)

Sends a new millivolts value to be output on DAC (Along with config settings).

For 12 bit models only.

Parameters
channel_atrue = Channel A, false = Channel B.
millivoltsmV value to be output by DAC. Ensure that this value doesn't exceed the maxixum for the DAC model and gain setting.
fractionaltrue = millivolts value has 0.5mV added to it. Only to be used when gain_low is true.

Definition at line 189 of file mcp48x2_dac.c.

192{
193 if (channel_a)
194 {
195 if(p_config_global->channel_a.gain_low)
196 {
197 p_config_global->channel_a.level =
198 (millivolts << (TWELVE_BIT_MV_OFFSET + 1));
199 // Add the 0.5mV value if required.
200 if (fractional == true)
201 {
202 p_config_global->channel_a.level += 1;
203 }
204 }
205 else
206 {
207 p_config_global->channel_a.level =
208 (millivolts << TWELVE_BIT_MV_OFFSET);
209 }
210 }
211 else
212 {
213 if(p_config_global->channel_b.gain_low)
214 {
215 p_config_global->channel_b.level =
216 (millivolts << (TWELVE_BIT_MV_OFFSET + 1));
217 // Add the 0.5mV value if required.
218 if (fractional == true)
219 {
220 p_config_global->channel_b.level += 1;
221 }
222 }
223 else
224 {
225 p_config_global->channel_b.level =
226 (millivolts << TWELVE_BIT_MV_OFFSET);
227 }
228 }
229
230 // Send new values to DAC
232}

◆ dac_reconfigure()

void dac_reconfigure ( void  )

Applies new config settings.

This function takes updated config settings for both channels of DAC, then re-sends data so that the new settings take effect.

Definition at line 240 of file mcp48x2_dac.c.

241{
242 uint16_t channel_a_data = 0;
243 uint16_t channel_b_data = 0;
244
245 // Set up config bits in 16bit word to be sent.
246 channel_a_data &= ~(1 << CHANNEL_BIT); // Clear channel bit (Channel A).
247 channel_a_data |= (p_config_global->channel_a.gain_low << GAIN_BIT);
248 channel_a_data |= (p_config_global->channel_a.active << SHUTDOWN_BIT);
249
250 channel_b_data |= (1 << CHANNEL_BIT); // Set channel bit (Channel B).
251 channel_b_data |= (p_config_global->channel_b.gain_low << GAIN_BIT);
252 channel_b_data |= (p_config_global->channel_b.active << SHUTDOWN_BIT);
253
254 // Shift level into correct place for chip and OR it into our 16bit word.
255 channel_a_data |=
256 (p_config_global->channel_a.level << level_resolution_shift);
257
258 channel_b_data |=
259 (p_config_global->channel_b.level << level_resolution_shift);
260
261
262 // Send data for channel A to DAC over SPI.
263 chip_select();
264 spi_trade_word(channel_a_data);
266
267 // Send data for channel B to DAC over SPI.
268 chip_select();
269 spi_trade_word(channel_b_data);
271
272 // If sync_manually is set to false, pulse LDAC to update values.
273 if (!p_config_global->sync_manually)
274 {
275 pulse_latch();
276 }
277}
uint16_t spi_trade_word(uint16_t data)
Sends out a 16bit word of data over spi (in two bytes) and returns the byte it receives.
Definition: atmega_spi.c:98
void chip_select(void)
Private helper function - pulls CS line (Chip Select) low in order to begin SPI communication with DA...
Definition: mcp48x2_dac.c:302
void chip_deselect(void)
Private helper function - pulls CS line (Chip Select) high to signal the end of SPI communication wit...
Definition: mcp48x2_dac.c:311
void pulse_latch(void)
Pulses LDAC pin low for a brief time (1uS).
Definition: mcp48x2_dac.c:286

◆ pulse_latch()

void pulse_latch ( void  )

Pulses LDAC pin low for a brief time (1uS).

When sync_manually is true, call this function to latch both config settings and new voltage value into both channels of DAC simultaneously.

Definition at line 286 of file mcp48x2_dac.c.

287{
288 DAC_CTRL_PORT &= ~(1 << LDAC);
289 _delay_us(1);
290 DAC_CTRL_PORT |= (1 << LDAC);
291}