|
|
|
/**
|
|
|
|
* Texas Instruments HDQ implementation for the Arduino API
|
|
|
|
* (cleft) Matthieu Lalonde 2008 (matth@mlalonde.net)
|
|
|
|
* Creative Commons BY-SA-NC
|
|
|
|
*
|
|
|
|
* http://trac.mlalonde.net/cral/browser/HDQ/
|
|
|
|
*
|
|
|
|
* Revision 1
|
|
|
|
*
|
|
|
|
**/
|
|
|
|
|
|
|
|
/* ***************** *
|
|
|
|
* HDQ Usage example *
|
|
|
|
** ***************** *
|
|
|
|
|
|
|
|
#include "hdq.h"
|
|
|
|
HDQ HDQ(HDQ_DEFAULT_PIN);
|
|
|
|
|
|
|
|
uint8_t r;
|
|
|
|
|
|
|
|
for (uint8_t jj = 0; jj < 0x10; jj++) {
|
|
|
|
r = HDQ.read(jj);
|
|
|
|
|
|
|
|
Serial.print("Register 0x");
|
|
|
|
Serial.print(jj, HEX);
|
|
|
|
Serial.print(": ");
|
|
|
|
Serial.print(r, BIN);
|
|
|
|
Serial.print(" 0x");
|
|
|
|
Serial.println(r, HEX);
|
|
|
|
}
|
|
|
|
|
|
|
|
r = HDQ.read(0x1e);
|
|
|
|
|
|
|
|
Serial.print("Register 0x1e: ");
|
|
|
|
Serial.print(r, BIN);
|
|
|
|
Serial.print(" 0x");
|
|
|
|
Serial.println(r, HEX);
|
|
|
|
|
|
|
|
r = HDQ.read(0x7e);
|
|
|
|
|
|
|
|
Serial.print("Register 0x7e: ");
|
|
|
|
Serial.print(r, BIN);
|
|
|
|
Serial.print(" 0x");
|
|
|
|
Serial.println(r, HEX);
|
|
|
|
|
|
|
|
HDQ.write(0x05, B11011101);
|
|
|
|
|
|
|
|
r = HDQ.read(0x05);
|
|
|
|
|
|
|
|
Serial.print("Register 0x05: ");
|
|
|
|
Serial.print(r, BIN);
|
|
|
|
Serial.print(" 0x");
|
|
|
|
Serial.println(r, HEX);
|
|
|
|
|
|
|
|
HDQ.write(0x05, B00111001);
|
|
|
|
|
|
|
|
r = HDQ.read(0x05);
|
|
|
|
|
|
|
|
Serial.print("Register 0x05: ");
|
|
|
|
Serial.print(r, BIN);
|
|
|
|
Serial.print(" 0x");
|
|
|
|
Serial.println(r, HEX);
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
#include "WConstants.h"
|
|
|
|
#include "pins_arduino.h"
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "avrmacros.h"
|
|
|
|
#include "hdq.h"
|
|
|
|
|
|
|
|
#define _HDQ_readPin() (*inputReg & bitmask)>>pin /* Change me to inline!*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
* @param pinArg: pin number to attach to
|
|
|
|
**/
|
|
|
|
HDQ::HDQ(uint8_t pinArg)
|
|
|
|
{
|
|
|
|
pin = pinArg;
|
|
|
|
port = digitalPinToPort(pin);
|
|
|
|
bitmask = digitalPinToBitMask(pin);
|
|
|
|
outputReg = portOutputRegister(port);
|
|
|
|
inputReg = portInputRegister(port);
|
|
|
|
modeReg = portModeRegister(port);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* sendBreak: writes a break to the HDQ line
|
|
|
|
**/
|
|
|
|
void HDQ::doBreak(void)
|
|
|
|
{
|
|
|
|
sbi(*modeReg, pin); // Set pin as output
|
|
|
|
|
|
|
|
// Singal a break on the line
|
|
|
|
cbi(*outputReg, pin); // Bring pin low
|
|
|
|
delayMicroseconds(HDQ_DELAY_TB);
|
|
|
|
|
|
|
|
// Make sure we leave enough time for the slave to recover
|
|
|
|
cbi(*modeReg, pin); // Release pin
|
|
|
|
delayMicroseconds(HDQ_DELAY_TBR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* writeByte: write a raw byte of data to the bus
|
|
|
|
* @param payload: the byte to send
|
|
|
|
*
|
|
|
|
**/
|
|
|
|
void HDQ::writeByte(uint8_t payload)
|
|
|
|
{
|
|
|
|
sbi(*modeReg, pin); // Set pin as output
|
|
|
|
|
|
|
|
for (uint8_t ii = 0; ii < 8; ii++)
|
|
|
|
{
|
|
|
|
// Start bit
|
|
|
|
cbi(*outputReg, pin); // Bring pin low
|
|
|
|
delayMicroseconds(HDQ_DELAY_BIT_START);
|
|
|
|
|
|
|
|
// Toggle the pin for this bit, LSB first
|
|
|
|
if (payload>>ii & 0x01) {
|
|
|
|
sbi(*outputReg, pin); // High
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cbi(*outputReg, pin); // Low
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bit time
|
|
|
|
delayMicroseconds(HDQ_DELAY_BIT_WRITE);
|
|
|
|
|
|
|
|
// Stop bit
|
|
|
|
sbi(*outputReg, pin); // Bring the pin high
|
|
|
|
delayMicroseconds(HDQ_DELAY_BIT_END);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* write: send a payload to the device
|
|
|
|
* @param reg: the address of the register to write to
|
|
|
|
* @param payload: data to be sent
|
|
|
|
* @return: false, unless if verif is set, then
|
|
|
|
* it will read back the register and
|
|
|
|
* return true if it matches the payload
|
|
|
|
**/
|
|
|
|
boolean HDQ::write(uint8_t reg, uint8_t payload)
|
|
|
|
{
|
|
|
|
// Singal a break
|
|
|
|
HDQ::doBreak();
|
|
|
|
|
|
|
|
// Write the register to write
|
|
|
|
HDQ::writeByte((reg |= HDQ_ADDR_MASK_WRITE));
|
|
|
|
|
|
|
|
// Wait for the slave to finish reading the register
|
|
|
|
delayMicroseconds((HDQ_DELAY_TRSPS_MAX - HDQ_DELAY_BIT_TOTAL) / 2);
|
|
|
|
|
|
|
|
// Write the payload
|
|
|
|
HDQ::writeByte(payload);
|
|
|
|
|
|
|
|
// Wait for the slave to finish writing the payload
|
|
|
|
delayMicroseconds((HDQ_DELAY_TRSPS_MAX - HDQ_DELAY_BIT_TOTAL) / 2);
|
|
|
|
|
|
|
|
cbi(*modeReg, pin); // Release pin
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Write with verification
|
|
|
|
**/
|
|
|
|
boolean HDQ::write(uint8_t reg, uint8_t payload, boolean verif)
|
|
|
|
{
|
|
|
|
// Write the payload
|
|
|
|
HDQ::write(reg, payload);
|
|
|
|
|
|
|
|
// Verify the write
|
|
|
|
if (payload == HDQ::read(reg)) return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* read: read from the device
|
|
|
|
* @param register: address of the register to read
|
|
|
|
* @return a uint8_t integer
|
|
|
|
**/
|
|
|
|
uint8_t HDQ::read(uint8_t reg)
|
|
|
|
{
|
|
|
|
uint8_t result = 0;
|
|
|
|
uint8_t maxTries = HDQ_DELAY_FAIL_TRIES; // ~128uS at 8Mhz with 8 instructions per loop
|
|
|
|
uint8_t ii;
|
|
|
|
|
|
|
|
// Singal a break
|
|
|
|
HDQ::doBreak();
|
|
|
|
|
|
|
|
// Write the register to read
|
|
|
|
HDQ::writeByte((reg |= HDQ_ADDR_MASK_READ));
|
|
|
|
|
|
|
|
for (ii = 0; ii < 8; ii++)
|
|
|
|
{
|
|
|
|
// Wait for the slave to toggle a low, or fail
|
|
|
|
maxTries = HDQ_DELAY_FAIL_TRIES;
|
|
|
|
while (_HDQ_readPin() != 0 && maxTries-- > 0)
|
|
|
|
if (maxTries == 1) return 0xFF;
|
|
|
|
|
|
|
|
// Wait until Tdsub and half or one bit has passed
|
|
|
|
delayMicroseconds(HDQ_DELAY_BIT_WRITE / 2 + HDQ_DELAY_BIT_START);
|
|
|
|
|
|
|
|
// Read the bit
|
|
|
|
result |= _HDQ_readPin()<<ii;
|
|
|
|
|
|
|
|
// Wait until Tssub has passed
|
|
|
|
delayMicroseconds(HDQ_DELAY_TSSUB - (HDQ_DELAY_BIT_WRITE / 2 + HDQ_DELAY_BIT_START) + 10);
|
|
|
|
|
|
|
|
// Wait for the slave to toggle a high, or fail
|
|
|
|
maxTries = HDQ_DELAY_FAIL_TRIES;
|
|
|
|
while (_HDQ_readPin() != 1 && maxTries-- > 0)
|
|
|
|
if (maxTries == 1) return 0xFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|