|
| 1 | +# Debugging I2C |
| 2 | + |
| 3 | +With the release of Arduino-ESP32 V1.0.1 the I2C subsystem contains code to exhaustively report communication errors. |
| 4 | +* Basic debugging can be enable by setting the *CORE DEBUG LEVEL* at or above *ERROR*. All errors will be directed the the *DEBUG OUTPUT* normally connected to `Serial()`. |
| 5 | +* Enhanced debugging can be used to generate specified information at specific positions during the i2c communication sequence. Increase *CORE DEBUG LEVEL* to ***DEBUG*** |
| 6 | + |
| 7 | +## Enable Debug Buffer |
| 8 | +The Enhanced debug features are enabled by uncommenting the `\\#define ENABLE_I2C_DEBUG_BUFFER` at line 45 of `esp32-hal-i2c.c`. |
| 9 | +* When Arduino-Esp32 is installed in Windows with Arduino Boards Manager, `esp32-hal-i2c.c` can be found in: |
| 10 | +`C:\Users\{user}\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.1\cores\esp32\` |
| 11 | +* When Arduino-Esp32 Development version is installed from GitHub, `esp32-hal-i2c.c` can be found in: |
| 12 | +`{arduino Sketch}\hardware\espressif\esp32\cores\esp32\` |
| 13 | + |
| 14 | + |
| 15 | +```c++ |
| 16 | +//#define ENABLE_I2C_DEBUG_BUFFER |
| 17 | +``` |
| 18 | +Change it to: |
| 19 | +```c++ |
| 20 | +#define ENABLE_I2C_DEBUG_BUFFER |
| 21 | +``` |
| 22 | +and recompile/upload the resulting code to your ESP32. |
| 23 | + |
| 24 | +Enabling this `#define` will consume an additional 2570 bytes of RAM and include a commensurate amount of code FLASH. If you see the message `"Debug Buffer not Enabled"` in your console log I would suggest you un-comment the line and regenerate the error. Additional information will be supplied on the log console. |
| 25 | + |
| 26 | +## Manually controlled Debugging |
| 27 | +Manual logging of the i2c control data buffers can be accomplished by using the debug control function of `Wire()`: |
| 28 | +```c++ |
| 29 | + uint32_t setDebugFlags( uint32_t setBits, uint32_t resetBits); |
| 30 | +``` |
| 31 | +`setBits`, and `resetBits` manually cause output of the control structures to the log console. They are bit fields that enable/disable the reporting of individual control structures during specific phases of the i2c communications sequence. The 32bit values are divided into four 8bit fields. Currently only five bits are defined. ***If an error is detected during normal operations, the relevant control structure will bit added to the log irrespective of the current debug flags.*** |
| 32 | +
|
| 33 | +* **bit 0** causes DumpI2c to execute |
| 34 | +header information about current communications event, |
| 35 | +and the dataQueue elements showing the logical i2c transaction commands |
| 36 | +* **bit 1** causes DumpInts to execute |
| 37 | +Actual sequence of interrupts handled during last communications event, cleared on entry into `ProcQueue()`. |
| 38 | +* **bit 2** causes DumpCmdqueue to execute |
| 39 | +The last block of commands to the i2c peripheral. |
| 40 | +* **bit 3** causes DumpStatus to execute |
| 41 | +A descriptive display of the 32bit i2c peripheral status word. |
| 42 | +* **bit 4** causes DumpFifo to execute |
| 43 | +A buffer listing the sequence of data added to the txFifo of the i2c peripheral. |
| 44 | +
|
| 45 | +Of the four division, only three are currently implemented: |
| 46 | +* 0xXX - - - - - - : at entry of ProcQueue (`bitFlags << 24`) |
| 47 | +* 0x - - XX - - - - : at exit of ProcQueue (`bitFlags << 16`) |
| 48 | +* 0x - - - - - - XX : at entry of Flush (`bitFlags`) |
| 49 | + |
| 50 | +For example, to display the sequence of Interrupts processed during the i2c communication transaction, **bit 1** would be set, and, since this information on Interrupt usage would only be valid after the communications have completed, the locus would be *at exit of ProcQueue*. The following code would be necessary. |
| 51 | +### code |
| 52 | +```c++ |
| 53 | +uint8_t flag = 1 << 1; // turn on bit 1 |
| 54 | +uint32_t debugFlag = flag << 16; // correctly position the 8bits of flag as the second byte of setBits. |
| 55 | +Wire.setDebugFlags(debugFlag,0);// resetBits=0 says leave all current setBits as is. |
| 56 | +
|
| 57 | +Wire.requestFrom(id,byteCount); // read byteCount bytes from slave at id |
| 58 | +
|
| 59 | +Wire.setDebugFlags(0,debugFlag); // don't add any new debug, remove debugFlag |
| 60 | +``` |
| 61 | +### output of log console |
| 62 | +``` |
| 63 | +[I][esp32-hal-i2c.c:437] i2cTriggerDumps(): after ProcQueue |
| 64 | +[I][esp32-hal-i2c.c:346] i2cDumpInts(): 0 row count INTR TX RX Tick |
| 65 | +[I][esp32-hal-i2c.c:350] i2cDumpInts(): [01] 0x0001 0x0002 0x0003 0x0000 0x005baac5 |
| 66 | +[I][esp32-hal-i2c.c:350] i2cDumpInts(): [02] 0x0001 0x0200 0x0000 0x0000 0x005baac5 |
| 67 | +[I][esp32-hal-i2c.c:350] i2cDumpInts(): [03] 0x0001 0x0080 0x0000 0x0008 0x005baac6 |
| 68 | +``` |
| 69 | +# Debug Log example |
| 70 | +### Code |
| 71 | +To read eight bytes of data from a DS1307 RTCC |
| 72 | +``` |
| 73 | + uint32_t debugFlag = 0x001F0000; |
| 74 | + uint8_t ID = 0x68; |
| 75 | + uint8_t block=8; |
| 76 | + |
| 77 | + if(debugFlag >0){ |
| 78 | + Wire.setDebugFlags(debugFlag,0); |
| 79 | + } |
| 80 | +
|
| 81 | + Wire.beginTransmission(ID); |
| 82 | + Wire.write(lowByte(addr)); |
| 83 | + if((err=Wire.endTransmission(false))!=0) { |
| 84 | + Serial.printf(" EndTransmission=%d(%s)",Wire.lastError(),Wire.getErrorText(Wire.lastError())); |
| 85 | +
|
| 86 | + if(err!=2) { |
| 87 | + Serial.printf(", resetting\n"); |
| 88 | + if( !Wire.begin()) Serial.printf(" Reset Failed\n"); |
| 89 | + if(debugFlag >0) Wire.setDebugFlags(0,debugFlag); |
| 90 | + return; |
| 91 | + } else { |
| 92 | + Serial.printf(", No Device present, aborting\n"); |
| 93 | + currentCommand= NO_COMMAND; |
| 94 | + return; |
| 95 | + } |
| 96 | + } |
| 97 | + err = Wire.requestFrom(ID,block,true); |
| 98 | + if(debugFlag >0){ |
| 99 | + Wire.setDebugFlags(0,debugFlag); |
| 100 | + } |
| 101 | +``` |
| 102 | +### output of log console |
| 103 | +``` |
| 104 | +[I][esp32-hal-i2c.c:437] i2cTriggerDumps(): after ProcQueue |
| 105 | +[E][esp32-hal-i2c.c:318] i2cDumpI2c(): i2c=0x3ffbdc78 |
| 106 | +[I][esp32-hal-i2c.c:319] i2cDumpI2c(): dev=0x60013000 date=0x16042000 |
| 107 | +[I][esp32-hal-i2c.c:321] i2cDumpI2c(): lock=0x3ffb843c |
| 108 | +[I][esp32-hal-i2c.c:323] i2cDumpI2c(): num=0 |
| 109 | +[I][esp32-hal-i2c.c:324] i2cDumpI2c(): mode=1 |
| 110 | +[I][esp32-hal-i2c.c:325] i2cDumpI2c(): stage=3 |
| 111 | +[I][esp32-hal-i2c.c:326] i2cDumpI2c(): error=1 |
| 112 | +[I][esp32-hal-i2c.c:327] i2cDumpI2c(): event=0x3ffb85c4 bits=10 |
| 113 | +[I][esp32-hal-i2c.c:328] i2cDumpI2c(): intr_handle=0x3ffb85f4 |
| 114 | +[I][esp32-hal-i2c.c:329] i2cDumpI2c(): dq=0x3ffb858c |
| 115 | +[I][esp32-hal-i2c.c:330] i2cDumpI2c(): queueCount=2 |
| 116 | +[I][esp32-hal-i2c.c:331] i2cDumpI2c(): queuePos=1 |
| 117 | +[I][esp32-hal-i2c.c:332] i2cDumpI2c(): errorByteCnt=0 |
| 118 | +[I][esp32-hal-i2c.c:333] i2cDumpI2c(): errorQueue=0 |
| 119 | +[I][esp32-hal-i2c.c:334] i2cDumpI2c(): debugFlags=0x001F0000 |
| 120 | +[I][esp32-hal-i2c.c:288] i2cDumpDqData(): [0] 7bit 68 W buf@=0x3ffc04b2, len=1, pos=1, ctrl=11101 |
| 121 | +[I][esp32-hal-i2c.c:306] i2cDumpDqData(): 0x0000: . 00 |
| 122 | +[I][esp32-hal-i2c.c:288] i2cDumpDqData(): [1] 7bit 68 R STOP buf@=0x3ffc042c, len=8, pos=8, ctrl=11111 |
| 123 | +[I][esp32-hal-i2c.c:306] i2cDumpDqData(): 0x0000: 5P...... 35 50 07 06 13 09 18 00 |
| 124 | +[I][esp32-hal-i2c.c:346] i2cDumpInts(): 0 row count INTR TX RX Tick |
| 125 | +[I][esp32-hal-i2c.c:350] i2cDumpInts(): [01] 0x0001 0x0002 0x0003 0x0000 0x000073d5 |
| 126 | +[I][esp32-hal-i2c.c:350] i2cDumpInts(): [02] 0x0001 0x0200 0x0000 0x0000 0x000073d5 |
| 127 | +[I][esp32-hal-i2c.c:350] i2cDumpInts(): [03] 0x0001 0x0080 0x0000 0x0008 0x000073d6 |
| 128 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 0] Y RSTART val[0] exp[0] en[0] bytes[0] |
| 129 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 1] Y WRITE val[0] exp[0] en[1] bytes[1] |
| 130 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 2] Y WRITE val[0] exp[0] en[1] bytes[1] |
| 131 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 3] Y RSTART val[0] exp[0] en[0] bytes[0] |
| 132 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 4] Y WRITE val[0] exp[0] en[1] bytes[1] |
| 133 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 5] Y READ val[0] exp[0] en[0] bytes[7] |
| 134 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 6] Y READ val[1] exp[0] en[0] bytes[1] |
| 135 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 7] Y STOP val[0] exp[0] en[0] bytes[0] |
| 136 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 8] N RSTART val[0] exp[0] en[0] bytes[0] |
| 137 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 9] N RSTART val[0] exp[0] en[0] bytes[0] |
| 138 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [10] N RSTART val[0] exp[0] en[0] bytes[0] |
| 139 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [11] N RSTART val[0] exp[0] en[0] bytes[0] |
| 140 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [12] N RSTART val[0] exp[0] en[0] bytes[0] |
| 141 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [13] N RSTART val[0] exp[0] en[0] bytes[0] |
| 142 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [14] N RSTART val[0] exp[0] en[0] bytes[0] |
| 143 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [15] N RSTART val[0] exp[0] en[0] bytes[0] |
| 144 | +[I][esp32-hal-i2c.c:385] i2cDumpStatus(): ack(0) sl_rw(0) to(0) arb(0) busy(0) sl(1) trans(0) rx(0) tx(0) sclMain(5) scl(6) |
| 145 | +[I][esp32-hal-i2c.c:424] i2cDumpFifo(): WRITE 0x68 0 |
| 146 | +[I][esp32-hal-i2c.c:424] i2cDumpFifo(): READ 0x68 |
| 147 | +``` |
| 148 | +## Explaination of log output |
| 149 | +### DumpI2c |
| 150 | +``` |
| 151 | +[I][esp32-hal-i2c.c:437] i2cTriggerDumps(): after ProcQueue |
| 152 | +[E][esp32-hal-i2c.c:318] i2cDumpI2c(): i2c=0x3ffbdc78 |
| 153 | +[I][esp32-hal-i2c.c:319] i2cDumpI2c(): dev=0x60013000 date=0x16042000 |
| 154 | +[I][esp32-hal-i2c.c:321] i2cDumpI2c(): lock=0x3ffb843c |
| 155 | +[I][esp32-hal-i2c.c:323] i2cDumpI2c(): num=0 |
| 156 | +[I][esp32-hal-i2c.c:324] i2cDumpI2c(): mode=1 |
| 157 | +[I][esp32-hal-i2c.c:325] i2cDumpI2c(): stage=3 |
| 158 | +[I][esp32-hal-i2c.c:326] i2cDumpI2c(): error=1 |
| 159 | +[I][esp32-hal-i2c.c:327] i2cDumpI2c(): event=0x3ffb85c4 bits=10 |
| 160 | +[I][esp32-hal-i2c.c:328] i2cDumpI2c(): intr_handle=0x3ffb85f4 |
| 161 | +[I][esp32-hal-i2c.c:329] i2cDumpI2c(): dq=0x3ffb858c |
| 162 | +[I][esp32-hal-i2c.c:330] i2cDumpI2c(): queueCount=2 |
| 163 | +[I][esp32-hal-i2c.c:331] i2cDumpI2c(): queuePos=1 |
| 164 | +[I][esp32-hal-i2c.c:332] i2cDumpI2c(): errorByteCnt=0 |
| 165 | +[I][esp32-hal-i2c.c:333] i2cDumpI2c(): errorQueue=0 |
| 166 | +[I][esp32-hal-i2c.c:334] i2cDumpI2c(): debugFlags=0x001F0000 |
| 167 | +``` |
| 168 | +variable | description |
| 169 | +---- | ---- |
| 170 | +**i2c** | *memory address for control block* |
| 171 | +**dev** | *memory address for access to i2c peripheral registers* |
| 172 | +**date** | *revision date of peripheral silicon 2016, 42 week* |
| 173 | +**lock** | *hal lock handle* |
| 174 | +**num** | *0,1 which peripheral is being controlled* |
| 175 | +**mode** | *configuration of driver 0=none, 1=MASTER, 2=SLAVE, 3=MASTER and SLAVE* |
| 176 | +**stage** | *internal STATE of driver 0=not configured, 1=startup, 2=running, 3=done* |
| 177 | +**error** | *internal ERROR status 0=not configured, 1=ok, 2=error, 3=address NAK, 4=data NAK, 5=arbitration loss, 6=timeout* |
| 178 | +**event** | *handle for interprocess FreeRTOS eventSemaphore for communication between ISR and APP* |
| 179 | +**intr_handle** | *FreeRTOS handle for allocated interrupt* |
| 180 | +**dq** | *memory address for data queue control block* |
| 181 | +**queueCount** | *number of data operations in queue control block* |
| 182 | +**queuePos** | *last executed data block* |
| 183 | +**errorByteCnt** | *position in current data block when error occured -1=address byte* |
| 184 | +**errorQueue** | *queue that was executing when error occurred* |
| 185 | +**debugFlags** | *current specified error bits* |
| 186 | + |
| 187 | +### DQ data |
| 188 | +``` |
| 189 | +[I][esp32-hal-i2c.c:288] i2cDumpDqData(): [0] 7bit 68 W buf@=0x3ffc04b2, len=1, pos=1, ctrl=11101 |
| 190 | +[I][esp32-hal-i2c.c:306] i2cDumpDqData(): 0x0000: . 00 |
| 191 | +[I][esp32-hal-i2c.c:288] i2cDumpDqData(): [1] 7bit 68 R STOP buf@=0x3ffc042c, len=8, pos=8, ctrl=11111 |
| 192 | +[I][esp32-hal-i2c.c:306] i2cDumpDqData(): 0x0000: 5P...... 35 50 07 06 13 09 18 00 |
| 193 | +``` |
| 194 | +variable | description |
| 195 | +--- | --- |
| 196 | +**[n]** | *index of data queue element* |
| 197 | +**i2c address** | *7bit= 7bit i2c slave address, 10bit= 10bit i2c slave address* |
| 198 | +**direction** | *W=Write, R=READ* |
| 199 | +**STOP** | *command issued a I2C STOP, else if blank, a RESTART was issued by next dq element.* |
| 200 | +**buf@** | *pointer to data buffer* |
| 201 | +**len** | *length of data buffer* |
| 202 | +**pos** | *last position used in buffer* |
| 203 | +**ctrl** | *bit field for data queue control, this bits describe if all necessary commands have been added to peripheral command buffer. in order(START,ADDRESS_Write,DATA,STOP,ADDRESS_value* |
| 204 | +**0xnnnn** | *data buffer content, displayable followed by HEX, 32 bytes on a line.* |
| 205 | + |
| 206 | +### DumpInts |
| 207 | +``` |
| 208 | +[I][esp32-hal-i2c.c:346] i2cDumpInts(): 0 row count INTR TX RX Tick |
| 209 | +[I][esp32-hal-i2c.c:350] i2cDumpInts(): [01] 0x0001 0x0002 0x0003 0x0000 0x000073d5 |
| 210 | +[I][esp32-hal-i2c.c:350] i2cDumpInts(): [02] 0x0001 0x0200 0x0000 0x0000 0x000073d5 |
| 211 | +[I][esp32-hal-i2c.c:350] i2cDumpInts(): [03] 0x0001 0x0080 0x0000 0x0008 0x000073d6 |
| 212 | +``` |
| 213 | +variable | description |
| 214 | +---- | ---- |
| 215 | +**row** | *array index* |
| 216 | +**count** | *number of consecutive, duplicate interrupts* |
| 217 | +**INTR** | *bit value of active interrupt (from ..\esp32\tools\sdk\include\soc\soc\i2c_struct.h)* |
| 218 | +**TX** | *number of bytes added to txFifo* |
| 219 | +**RX** | *number of bytes read from rxFifo* |
| 220 | +**Tick** | *current tick counter from xTaskGetTickCountFromISR()* |
| 221 | + |
| 222 | +### DumpCmdQueue |
| 223 | +``` |
| 224 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 0] Y RSTART val[0] exp[0] en[0] bytes[0] |
| 225 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 1] Y WRITE val[0] exp[0] en[1] bytes[1] |
| 226 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 2] Y WRITE val[0] exp[0] en[1] bytes[1] |
| 227 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 3] Y RSTART val[0] exp[0] en[0] bytes[0] |
| 228 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 4] Y WRITE val[0] exp[0] en[1] bytes[1] |
| 229 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 5] Y READ val[0] exp[0] en[0] bytes[7] |
| 230 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 6] Y READ val[1] exp[0] en[0] bytes[1] |
| 231 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 7] Y STOP val[0] exp[0] en[0] bytes[0] |
| 232 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 8] N RSTART val[0] exp[0] en[0] bytes[0] |
| 233 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 9] N RSTART val[0] exp[0] en[0] bytes[0] |
| 234 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [10] N RSTART val[0] exp[0] en[0] bytes[0] |
| 235 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [11] N RSTART val[0] exp[0] en[0] bytes[0] |
| 236 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [12] N RSTART val[0] exp[0] en[0] bytes[0] |
| 237 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [13] N RSTART val[0] exp[0] en[0] bytes[0] |
| 238 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [14] N RSTART val[0] exp[0] en[0] bytes[0] |
| 239 | +[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [15] N RSTART val[0] exp[0] en[0] bytes[0] |
| 240 | +``` |
| 241 | +Column | description |
| 242 | +---- | ---- |
| 243 | +**command** | *RSTART= generate i2c START sequence, WRITE= output byte(s), READ= input byte(s), STOP= generate i2c STOP sequence, END= continuation flag for peripheral to pause execution waiting for a refilled command list* |
| 244 | +**val** | *value for ACK bit, 0 = LOW, 1= HIGH* |
| 245 | +**exp** | *test of ACK bit 0=no, 1=yes* |
| 246 | +**en** | *output of val, 0=no, 1=yes* |
| 247 | +**bytes** | *number of byte to send(WRITE) or receive(READ) 1..255* |
| 248 | + |
| 249 | +### DumpStatus |
| 250 | +``` |
| 251 | +[I][esp32-hal-i2c.c:385] i2cDumpStatus(): ack(0) sl_rw(0) to(0) arb(0) busy(0) sl(1) trans(0) rx(0) tx(0) sclMain(5) scl(6) |
| 252 | +``` |
| 253 | +variable | description |
| 254 | +---- | ---- |
| 255 | +**ack** | *last value for ACK bit* |
| 256 | +**sl_rw** | *mode for SLAVE operation 0=write, 1=read* |
| 257 | +**to** | *timeout* |
| 258 | +**arb** | *arbitration loss* |
| 259 | +**busy** | *bus is inuse by other Master, or SLAVE is holding SCL,SDA* |
| 260 | +**sl** | *last address on bus was equal to slave_addr* |
| 261 | +**trans** | *a byte has moved though peripheral* |
| 262 | +**rx** | *count of bytes in rxFifo* |
| 263 | +**tx** | *count of bytes in txFifo* |
| 264 | +**sclMain** | *state machine for i2c module. 0: SCL_MAIN_IDLE, 1: SCL_ADDRESS_SHIFT, 2: SCL_ACK_ADDRESS, 3: SCL_RX_DATA, 4: SCL_TX_DATA, 5: SCL_SEND_ACK, 6 :SCL_WAIT_ACK* |
| 265 | +**scl** | *SCL clock state. 0: SCL_IDLE, 1: SCL_START, 2: SCL_LOW_EDGE, 3: SCL_LOW, 4: SCL_HIGH_EDGE, 5: SCL_HIGH, 6:SCL_STOP* |
| 266 | + |
| 267 | +### DumpFifo |
| 268 | +``` |
| 269 | +[I][esp32-hal-i2c.c:424] i2cDumpFifo(): WRITE 0x68 0 |
| 270 | +[I][esp32-hal-i2c.c:424] i2cDumpFifo(): READ 0x68 |
| 271 | +``` |
| 272 | +Mode | datavalues |
| 273 | +--- | --- |
| 274 | +**WRITE** | the following bytes added to the txFifo are in response to a WRITE command |
| 275 | +**READ** | the following bytes added to the txFifo are in response to a READ command |
| 276 | + |
0 commit comments