Skip to content

Commit

Permalink
dac working, added example
Browse files Browse the repository at this point in the history
  • Loading branch information
ost-ing committed Apr 10, 2021
1 parent c4ee9be commit 8cf0328
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 86 deletions.
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,28 @@ A platform agnostic library for the Texas Instruments DAC8568.
## features

- Support for Texas Instruments DAC8568
- Limited subset of DAC8568 features supported
- Full no-std support
- Implemented with embedded-hal (https://docs.rs/embedded-hal/0.2.3/embedded_hal)
- Implemented with `embedded-hal` (https://docs.rs/embedded-hal/0.2.3/embedded_hal)
- Blocking and non-blocking support

## example

Note: Quick example based on the `stm32h7xx-hal`.
Note: Quick example based on the `stm32h7xx-hal`.

```rust
// Initialise NSS for SPI communications
let spi = ...;
let nss = nss.into_push_pull_output();
// Initialize the dac instance
let mut dac = dac8568::Dac::new(nss);
dac.enable();
// Get a "write" message to set the voltage of a given channel
let message = dac8568::Message::get_write_message(dac8568::Channel::A, voltage);
// Now transfer the data either as a blocking call
dac.write_blocking(spi, message).unwrap();
// or prepare the data for a DMA transfer
dac.prepare_transfer(message, |payload| {
// begin DMA transfer with bytes payload
});
```
Binary file added documentation/dac8568.pdf
Binary file not shown.
Binary file added documentation/dac8568_ssop16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added documentation/oscilloscope_capture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
187 changes: 103 additions & 84 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

use embedded_hal::digital::v2::OutputPin;

pub enum ChannelSelect {
pub enum Channel {
A = 0,
B = 1,
C = 2,
Expand All @@ -21,9 +21,25 @@ pub enum ChannelSelect {
BROADCAST = 9,
}

impl Channel {
pub fn from_index(index: u8) -> Channel {
match index {
0 => Channel::A,
1 => Channel::B,
2 => Channel::C,
3 => Channel::D,
4 => Channel::E,
5 => Channel::F,
6 => Channel::G,
7 => Channel::H,
_ => panic!("Unsupported index for dac8568 channel select"),
}
}
}

pub enum ControlType {
WriteToInputRegister = 0,
UpdateRegister = 1,
UpdateRegister = 1,
WriteToChannelAndUpdateAllRegisters = 2,
WriteToChannelAndUpdateSingleRegister = 3,
PowerDownComm = 4,
Expand All @@ -33,106 +49,71 @@ pub enum ControlType {
}

pub enum SetupMode {
Static = 8,
Flex = 9
Static = 8,
Flex = 9,
}

pub enum ClearCodeFeature {
ClearToZeroScale = 0,
ClearToMidScale = 1,
ClearToFullScale = 2,
IgnoreClearPin = 3,
ClearToZeroScale = 0,
ClearToMidScale = 1,
ClearToFullScale = 2,
IgnoreClearPin = 3,
}

pub enum InternalRefCommFeature {
PowerDownIntRefStatic = 0,
PowerUpIntRefStatic = 1,
// PowerUpIntRefFlex = 0,
// PowerUpIntRefAlwaysFlex = 0,
// PowerDownIntRefFlex = 0,
// SwitchFromFlexToStatic = 0
}
PowerDownIntRefStatic = 0,
PowerUpIntRefStatic = 1,
// PowerUpIntRefFlex = 0,
// PowerUpIntRefAlwaysFlex = 0,
// PowerDownIntRefFlex = 0,
// SwitchFromFlexToStatic = 0
}

/// TODO
pub enum Register {
A = 1,
B = 2,
C = 4,
D = 8,
E = 16,
F = 32,
G = 64,
H = 128
A = 1,
B = 2,
C = 4,
D = 8,
E = 16,
F = 32,
G = 64,
H = 128,
}

/// TODO
pub enum PowerModes {
PowerUp = 0,
PowerDown1KToGround = 16,
PowerDown100KToGround = 32,
PowerDownHighZToGround = 48
PowerUp = 0,
PowerDown1KToGround = 16,
PowerDown100KToGround = 32,
PowerDownHighZToGround = 48,
}

/// TODO
pub enum InternalRefCommData {
Default = 0,
PowerUpIntRefFlex = 32768,
PowerUpIntRefAlwaysFlex = 40960,
PowerDownIntRefFlex = 49152,
Default = 0,
PowerUpIntRefFlex = 32768,
PowerUpIntRefAlwaysFlex = 40960,
PowerDownIntRefFlex = 49152,
}

///

/// The Message that is eventually serialized and transmitted to the DAC
/// The inputshiftregister (SR) of the DAC7568,DAC8168,and DAC8568
/// is 32 bits wide(as shown in Table1, Table2, and Table3, respectively),
/// and consists of four Prefix bits (DB31 to DB28),
/// four control bits (DB27 to DB24), 16 databits (DB23 to DB4),
/// and four additional feature bits. The 16 databits comprise the 16-, 14-, or 12-bit input code
pub struct Message {
feature: u8, // 4 bits
/// Todo, only DAC8568 is supported. DAC7568 = 12, DAC8168 = 14
data: u16, // data
address: u8, // 4 bits
prefix: u8, // 4 bits
control: u8, // 4 bits
prefix: u8, // 4 bits
address: u8, // 4 bits
data: u16, // 16 bits
feature: u8, // 4 bits
}

impl Message {
fn get_payload(&self) -> [u8; 4] {
[self.prefix, self.control, self.address, (self.data << 8) as u8, (self.data << 0) as u8, self.feature]
}
}

/// DAC8568
pub struct Dac<NSS, LDAC, CLR> {
nss: NSS,
ldac: LDAC,
clear: CLR,
active: bool,
}

/// DAC Related errors
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum DacError {
/// Unable to write to bus
BusWriteError,
}


impl<NSS, LDAC, CLR> Dac<NSS, LDAC, CLR>
where
NSS: OutputPin,
LDAC: OutputPin,
CLR: OutputPin,
{
/// Initialize a new instance of dac8568
pub fn new(nss: NSS, ldac: LDAC, clear: CLR) -> Self {
Self {
nss,
ldac,
clear,
active: false,
}
}

pub fn get_power_message(mode: PowerModes, channel: u8) -> Message {
Message {
prefix: 0,
Expand All @@ -143,7 +124,11 @@ where
}
}

pub fn get_enable_message(control: ControlType, data: InternalRefCommData, feature: InternalRefCommFeature) -> Message {
pub fn get_enable_message(
control: ControlType,
data: InternalRefCommData,
feature: InternalRefCommFeature,
) -> Message {
Message {
prefix: 0,
control: control as u8,
Expand All @@ -153,7 +138,7 @@ where
}
}

pub fn get_write_message(channel: ChannelSelect, value: u16) -> Message {
pub fn get_write_message(channel: Channel, value: u16) -> Message {
Message {
prefix: 0,
feature: 0,
Expand All @@ -163,14 +148,48 @@ where
}
}

fn get_payload(&self) -> [u8; 4] {
let mut payload: u32 = 0x00;
payload = payload | ((self.prefix as u32) << 28);
payload = payload | ((self.control as u32) << 24);
payload = payload | ((self.address as u32) << 20);
payload = payload | ((self.data as u32) << 4);
payload = payload | ((self.feature as u32) << 0);
payload.to_be_bytes()
}
}

/// DAC8568
pub struct Dac<NSS> {
nss: NSS,
active: bool,
}

/// DAC Related errors
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum DacError {
/// Unable to write to bus
BusWriteError,
}

impl<NSS> Dac<NSS>
where
NSS: OutputPin,
{
/// Initialize a new instance of dac8568
pub fn new(nss: NSS) -> Self {
Self { nss, active: false }
}

pub fn enable(&mut self) {
self.active = true;
}

/// For asynchronous communication methods (e.g. Interrupt or DMA), this function
/// prepares the DAC for the transfer, generates the command and passes it back to the initiator
/// via the callback parameter
pub fn prepare_transfer<F: FnMut([u8; 4]) -> ()>(
&mut self,
message: Message,
mut callback: F,
) {
pub fn prepare_transfer<F: FnMut([u8; 4]) -> ()>(&mut self, message: Message, mut callback: F) {
if !self.active {
return;
}
Expand All @@ -179,13 +198,13 @@ where
self.nss.set_low().unwrap_or_default();
callback(command);
self.nss.set_high().unwrap_or_default();
}
}

/// Write to the DAC via a blocking call on the specified SPI interface
pub fn write_blocking(
&mut self,
spi: &mut dyn embedded_hal::blocking::spi::Write<u8, Error = ()>,
message: Message
message: Message,
) -> Result<(), DacError> {
if !self.active {
return Ok(());
Expand Down

0 comments on commit 8cf0328

Please sign in to comment.