| 1 | /** |
|---|
| 2 | * Texas Instruments HDQ implementation for the Arduino API |
|---|
| 3 | * (cleft) Matthieu Lalonde 2008 (matth@mlalonde.net) |
|---|
| 4 | * Creative Commons BY-SA-NC |
|---|
| 5 | * |
|---|
| 6 | * http://trac.mlalonde.net/cral/browser/HDQ/ |
|---|
| 7 | * |
|---|
| 8 | * Revision 1 |
|---|
| 9 | * |
|---|
| 10 | **/ |
|---|
| 11 | |
|---|
| 12 | /* ***************** * |
|---|
| 13 | * HDQ Usage example * |
|---|
| 14 | ** ***************** * |
|---|
| 15 | |
|---|
| 16 | #include "hdq.h" |
|---|
| 17 | HDQ HDQ(HDQ_DEFAULT_PIN); |
|---|
| 18 | |
|---|
| 19 | uint8_t r; |
|---|
| 20 | |
|---|
| 21 | for (uint8_t jj = 0; jj < 0x10; jj++) { |
|---|
| 22 | r = HDQ.read(jj); |
|---|
| 23 | |
|---|
| 24 | Serial.print("Register 0x"); |
|---|
| 25 | Serial.print(jj, HEX); |
|---|
| 26 | Serial.print(": "); |
|---|
| 27 | Serial.print(r, BIN); |
|---|
| 28 | Serial.print(" 0x"); |
|---|
| 29 | Serial.println(r, HEX); |
|---|
| 30 | } |
|---|
| 31 | |
|---|
| 32 | r = HDQ.read(0x1e); |
|---|
| 33 | |
|---|
| 34 | Serial.print("Register 0x1e: "); |
|---|
| 35 | Serial.print(r, BIN); |
|---|
| 36 | Serial.print(" 0x"); |
|---|
| 37 | Serial.println(r, HEX); |
|---|
| 38 | |
|---|
| 39 | r = HDQ.read(0x7e); |
|---|
| 40 | |
|---|
| 41 | Serial.print("Register 0x7e: "); |
|---|
| 42 | Serial.print(r, BIN); |
|---|
| 43 | Serial.print(" 0x"); |
|---|
| 44 | Serial.println(r, HEX); |
|---|
| 45 | |
|---|
| 46 | HDQ.write(0x05, B11011101); |
|---|
| 47 | |
|---|
| 48 | r = HDQ.read(0x05); |
|---|
| 49 | |
|---|
| 50 | Serial.print("Register 0x05: "); |
|---|
| 51 | Serial.print(r, BIN); |
|---|
| 52 | Serial.print(" 0x"); |
|---|
| 53 | Serial.println(r, HEX); |
|---|
| 54 | |
|---|
| 55 | HDQ.write(0x05, B00111001); |
|---|
| 56 | |
|---|
| 57 | r = HDQ.read(0x05); |
|---|
| 58 | |
|---|
| 59 | Serial.print("Register 0x05: "); |
|---|
| 60 | Serial.print(r, BIN); |
|---|
| 61 | Serial.print(" 0x"); |
|---|
| 62 | Serial.println(r, HEX); |
|---|
| 63 | |
|---|
| 64 | */ |
|---|
| 65 | |
|---|
| 66 | extern "C" { |
|---|
| 67 | #include "WConstants.h" |
|---|
| 68 | #include "pins_arduino.h" |
|---|
| 69 | } |
|---|
| 70 | |
|---|
| 71 | #include "avrmacros.h" |
|---|
| 72 | #include "hdq.h" |
|---|
| 73 | |
|---|
| 74 | #define _HDQ_readPin() (*inputReg & bitmask)>>pin /* Change me to inline!*/ |
|---|
| 75 | |
|---|
| 76 | /** |
|---|
| 77 | * Constructor |
|---|
| 78 | * @param pinArg: pin number to attach to |
|---|
| 79 | **/ |
|---|
| 80 | HDQ::HDQ(uint8_t pinArg) |
|---|
| 81 | { |
|---|
| 82 | pin = pinArg; |
|---|
| 83 | port = digitalPinToPort(pin); |
|---|
| 84 | bitmask = digitalPinToBitMask(pin); |
|---|
| 85 | outputReg = portOutputRegister(port); |
|---|
| 86 | inputReg = portInputRegister(port); |
|---|
| 87 | modeReg = portModeRegister(port); |
|---|
| 88 | } |
|---|
| 89 | |
|---|
| 90 | /** |
|---|
| 91 | * sendBreak: writes a break to the HDQ line |
|---|
| 92 | **/ |
|---|
| 93 | void HDQ::doBreak(void) |
|---|
| 94 | { |
|---|
| 95 | sbi(*modeReg, pin); // Set pin as output |
|---|
| 96 | |
|---|
| 97 | // Singal a break on the line |
|---|
| 98 | cbi(*outputReg, pin); // Bring pin low |
|---|
| 99 | delayMicroseconds(HDQ_DELAY_TB); |
|---|
| 100 | |
|---|
| 101 | // Make sure we leave enough time for the slave to recover |
|---|
| 102 | cbi(*modeReg, pin); // Release pin |
|---|
| 103 | delayMicroseconds(HDQ_DELAY_TBR); |
|---|
| 104 | } |
|---|
| 105 | |
|---|
| 106 | /** |
|---|
| 107 | * writeByte: write a raw byte of data to the bus |
|---|
| 108 | * @param payload: the byte to send |
|---|
| 109 | * |
|---|
| 110 | **/ |
|---|
| 111 | void HDQ::writeByte(uint8_t payload) |
|---|
| 112 | { |
|---|
| 113 | sbi(*modeReg, pin); // Set pin as output |
|---|
| 114 | |
|---|
| 115 | for (uint8_t ii = 0; ii < 8; ii++) |
|---|
| 116 | { |
|---|
| 117 | // Start bit |
|---|
| 118 | cbi(*outputReg, pin); // Bring pin low |
|---|
| 119 | delayMicroseconds(HDQ_DELAY_BIT_START); |
|---|
| 120 | |
|---|
| 121 | // Toggle the pin for this bit, LSB first |
|---|
| 122 | if (payload>>ii & 0x01) { |
|---|
| 123 | sbi(*outputReg, pin); // High |
|---|
| 124 | } |
|---|
| 125 | else { |
|---|
| 126 | cbi(*outputReg, pin); // Low |
|---|
| 127 | } |
|---|
| 128 | |
|---|
| 129 | // Bit time |
|---|
| 130 | delayMicroseconds(HDQ_DELAY_BIT_WRITE); |
|---|
| 131 | |
|---|
| 132 | // Stop bit |
|---|
| 133 | sbi(*outputReg, pin); // Bring the pin high |
|---|
| 134 | delayMicroseconds(HDQ_DELAY_BIT_END); |
|---|
| 135 | } |
|---|
| 136 | |
|---|
| 137 | return; |
|---|
| 138 | } |
|---|
| 139 | |
|---|
| 140 | /** |
|---|
| 141 | * write: send a payload to the device |
|---|
| 142 | * @param reg: the address of the register to write to |
|---|
| 143 | * @param payload: data to be sent |
|---|
| 144 | * @return: false, unless if verif is set, then |
|---|
| 145 | * it will read back the register and |
|---|
| 146 | * return true if it matches the payload |
|---|
| 147 | **/ |
|---|
| 148 | boolean HDQ::write(uint8_t reg, uint8_t payload) |
|---|
| 149 | { |
|---|
| 150 | // Singal a break |
|---|
| 151 | HDQ::doBreak(); |
|---|
| 152 | |
|---|
| 153 | // Write the register to write |
|---|
| 154 | HDQ::writeByte((reg |= HDQ_ADDR_MASK_WRITE)); |
|---|
| 155 | |
|---|
| 156 | // Wait for the slave to finish reading the register |
|---|
| 157 | delayMicroseconds((HDQ_DELAY_TRSPS_MAX - HDQ_DELAY_BIT_TOTAL) / 2); |
|---|
| 158 | |
|---|
| 159 | // Write the payload |
|---|
| 160 | HDQ::writeByte(payload); |
|---|
| 161 | |
|---|
| 162 | // Wait for the slave to finish writing the payload |
|---|
| 163 | delayMicroseconds((HDQ_DELAY_TRSPS_MAX - HDQ_DELAY_BIT_TOTAL) / 2); |
|---|
| 164 | |
|---|
| 165 | cbi(*modeReg, pin); // Release pin |
|---|
| 166 | |
|---|
| 167 | return true; |
|---|
| 168 | } |
|---|
| 169 | |
|---|
| 170 | /** |
|---|
| 171 | * Write with verification |
|---|
| 172 | **/ |
|---|
| 173 | boolean HDQ::write(uint8_t reg, uint8_t payload, boolean verif) |
|---|
| 174 | { |
|---|
| 175 | // Write the payload |
|---|
| 176 | HDQ::write(reg, payload); |
|---|
| 177 | |
|---|
| 178 | // Verify the write |
|---|
| 179 | if (payload == HDQ::read(reg)) return true; |
|---|
| 180 | |
|---|
| 181 | return false; |
|---|
| 182 | } |
|---|
| 183 | |
|---|
| 184 | |
|---|
| 185 | /** |
|---|
| 186 | * read: read from the device |
|---|
| 187 | * @param register: address of the register to read |
|---|
| 188 | * @return a uint8_t integer |
|---|
| 189 | **/ |
|---|
| 190 | uint8_t HDQ::read(uint8_t reg) |
|---|
| 191 | { |
|---|
| 192 | uint8_t result = 0; |
|---|
| 193 | uint8_t maxTries = HDQ_DELAY_FAIL_TRIES; // ~128uS at 8Mhz with 8 instructions per loop |
|---|
| 194 | uint8_t ii; |
|---|
| 195 | |
|---|
| 196 | // Singal a break |
|---|
| 197 | HDQ::doBreak(); |
|---|
| 198 | |
|---|
| 199 | // Write the register to read |
|---|
| 200 | HDQ::writeByte((reg |= HDQ_ADDR_MASK_READ)); |
|---|
| 201 | |
|---|
| 202 | for (ii = 0; ii < 8; ii++) |
|---|
| 203 | { |
|---|
| 204 | // Wait for the slave to toggle a low, or fail |
|---|
| 205 | maxTries = HDQ_DELAY_FAIL_TRIES; |
|---|
| 206 | while (_HDQ_readPin() != 0 && maxTries-- > 0) |
|---|
| 207 | if (maxTries == 1) return 0xFF; |
|---|
| 208 | |
|---|
| 209 | // Wait until Tdsub and half or one bit has passed |
|---|
| 210 | delayMicroseconds(HDQ_DELAY_BIT_WRITE / 2 + HDQ_DELAY_BIT_START); |
|---|
| 211 | |
|---|
| 212 | // Read the bit |
|---|
| 213 | result |= _HDQ_readPin()<<ii; |
|---|
| 214 | |
|---|
| 215 | // Wait until Tssub has passed |
|---|
| 216 | delayMicroseconds(HDQ_DELAY_TSSUB - (HDQ_DELAY_BIT_WRITE / 2 + HDQ_DELAY_BIT_START) + 10); |
|---|
| 217 | |
|---|
| 218 | // Wait for the slave to toggle a high, or fail |
|---|
| 219 | maxTries = HDQ_DELAY_FAIL_TRIES; |
|---|
| 220 | while (_HDQ_readPin() != 1 && maxTries-- > 0) |
|---|
| 221 | if (maxTries == 1) return 0xFF; |
|---|
| 222 | } |
|---|
| 223 | |
|---|
| 224 | return result; |
|---|
| 225 | } |
|---|