parent
ad0c37b16e
commit
250bd4dc21
@ -0,0 +1,104 @@ |
||||
/* Control the mcp 4921/4922 DACs with hardware SPI of the Arduino UNO
|
||||
* ...without all the overhead of the Arduino SPI lib... |
||||
* Just the needed functions in a runtime optimized way by "Theremingenieur" Thierry Frenkel |
||||
* This file is free software: you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public License as published |
||||
* by the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
*/ |
||||
|
||||
#ifndef SPImcpDac_h |
||||
#define SPImcpDac_h |
||||
|
||||
#include <Arduino.h> |
||||
|
||||
// Data direction & Port register & Bit number for DAC Latch:
|
||||
#define MCP_DAC_LDAC_DDR DDRD |
||||
#define MCP_DAC_LDAC_PORT PORTD |
||||
#define MCP_DAC_LDAC_BIT 7 |
||||
// Data direction & Port register & Bit number for DAC CS
|
||||
#define MCP_DAC_CS_DDR DDRB |
||||
#define MCP_DAC_CS_PORT PORTB |
||||
#define MCP_DAC_CS_BIT 2 |
||||
// Data direction & Port register & Bit number for DAC2 CS
|
||||
#define MCP_DAC2_CS_DDR DDRB |
||||
#define MCP_DAC2_CS_PORT PORTB |
||||
#define MCP_DAC2_CS_BIT 1 |
||||
// Data direction & Port registers & Bit numbers for Hardware SPI
|
||||
#define HW_SPI_DDR DDRB |
||||
#define HW_SPI_SCK_BIT 5 |
||||
#define HW_SPI_MISO_BIT 4 // unused in this configuration
|
||||
#define HW_SPI_MOSI_BIT 3 |
||||
|
||||
static inline void SPImcpDACinit() |
||||
{ |
||||
// initialize the latch pin:
|
||||
MCP_DAC_LDAC_DDR |= _BV(MCP_DAC_LDAC_BIT); |
||||
MCP_DAC_LDAC_PORT |= _BV(MCP_DAC_LDAC_BIT); |
||||
// initialize the CS pins:
|
||||
MCP_DAC_CS_DDR |= _BV(MCP_DAC_CS_BIT); |
||||
MCP_DAC_CS_PORT |= _BV(MCP_DAC_CS_BIT); |
||||
MCP_DAC2_CS_DDR |= _BV(MCP_DAC2_CS_BIT); |
||||
MCP_DAC2_CS_PORT |= _BV(MCP_DAC2_CS_BIT); |
||||
// initialize the hardware SPI pins:
|
||||
HW_SPI_DDR |= _BV(HW_SPI_SCK_BIT); |
||||
HW_SPI_DDR |= _BV(HW_SPI_MOSI_BIT); |
||||
// initialize the hardware SPI registers
|
||||
SPCR = _BV(SPE) | _BV(MSTR); // no interrupt, SPI enable, MSB first, SPI master, SPI mode 0, clock = f_osc/4 (maximum)
|
||||
SPSR = _BV(SPI2X); // double the SPI clock, ideally we get 8 MHz, so that a 16bit word goes out in 3.5us (5.6us when called from an interrupt) including CS asserting/deasserting
|
||||
} |
||||
|
||||
static inline void SPImcpDACtransmit(uint16_t data) |
||||
{ |
||||
// Send highbyte and wait for complete
|
||||
SPDR = highByte(data); |
||||
asm("nop"); |
||||
while (!(SPSR & _BV(SPIF))) |
||||
; |
||||
// Send lowbyte and wait for complete
|
||||
SPDR = lowByte(data); |
||||
asm("nop"); |
||||
while (!(SPSR & _BV(SPIF))) |
||||
; |
||||
} |
||||
|
||||
static inline void SPImcpDAClatch() |
||||
{ |
||||
MCP_DAC_LDAC_PORT &= ~_BV(MCP_DAC_LDAC_BIT); |
||||
MCP_DAC_LDAC_PORT |= _BV(MCP_DAC_LDAC_BIT); |
||||
} |
||||
|
||||
static inline void SPImcpDACsend(uint16_t data) |
||||
{ |
||||
MCP_DAC_CS_PORT &= ~_BV(MCP_DAC_CS_BIT); |
||||
// Sanitize input data and add DAC config MSBs
|
||||
data &= 0x0FFF; |
||||
data |= 0x7000; |
||||
SPImcpDACtransmit(data); |
||||
MCP_DAC_CS_PORT |= _BV(MCP_DAC_CS_BIT); |
||||
// Do not latch immpediately, let's do it at the very beginning of the next interrupt to get consistent timing
|
||||
} |
||||
|
||||
static inline void SPImcpDAC2Asend(uint16_t data) |
||||
{ |
||||
MCP_DAC2_CS_PORT &= ~_BV(MCP_DAC2_CS_BIT); |
||||
// Sanitize input data and add DAC config MSBs
|
||||
data &= 0x0FFF; |
||||
data |= 0x7000; |
||||
SPImcpDACtransmit(data); |
||||
MCP_DAC2_CS_PORT |= _BV(MCP_DAC2_CS_BIT); |
||||
SPImcpDAClatch(); |
||||
} |
||||
|
||||
static inline void SPImcpDAC2Bsend(uint16_t data) |
||||
{ |
||||
MCP_DAC2_CS_PORT &= ~_BV(MCP_DAC2_CS_BIT); |
||||
// Sanitize input data and add DAC config MSBs
|
||||
data &= 0x0FFF; |
||||
data |= 0xF000; |
||||
SPImcpDACtransmit(data); |
||||
MCP_DAC2_CS_PORT |= _BV(MCP_DAC2_CS_BIT); |
||||
SPImcpDAClatch(); |
||||
} |
||||
|
||||
#endif |
Loading…
Reference in new issue