├── LICENSE ├── README.md ├── design ├── fp-info-cache ├── fp-lib-table ├── i2c-tester-cache.lib ├── i2c-tester.kicad_pcb ├── i2c-tester.net ├── i2c-tester.pdf ├── i2c-tester.pretty │ └── enclosure-i2c-tester.kicad_mod ├── i2c-tester.pro └── i2c-tester.sch ├── firmware ├── Makefile ├── V-USB-CommercialLicense.txt ├── V-USB-License.txt ├── asmcommon.inc ├── i2cdrv.c ├── i2cdrv.h ├── i2ctester.c ├── i2ctester.h ├── oddebug.c ├── oddebug.h ├── usbconfig.h ├── usbdrv.c ├── usbdrv.h ├── usbdrvasm.S ├── usbdrvasm.asm ├── usbdrvasm12.inc ├── usbdrvasm128.inc ├── usbdrvasm15.inc ├── usbdrvasm16.inc ├── usbdrvasm165.inc ├── usbdrvasm18-crc.inc ├── usbdrvasm20.inc └── usbportability.h ├── resources ├── enclosure-labels │ ├── top-label.pdf │ └── top-label.svg ├── i2c-tester-prototype-enc.jpg ├── i2c-tester-sample-connection.fzz └── i2c-tester-sample-connection.jpg └── terminal └── src ├── .vscode └── settings.json ├── Makefile ├── cmdproc.c ├── cmdproc.h ├── common.h ├── docuproc.c ├── docuproc.h ├── main.c ├── main.h ├── strdef.h ├── strdoc.h ├── termutil.c └── termutil.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Dilshan R Jayakody 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # I2C Master Mode Emulator 2 | 3 | ![Prototype version of I2C master mode emulator](resources/i2c-tester-prototype-enc.jpg) 4 | 5 | The I2C master mode emulator allows communication with I2C devices by sending or receiving data to/from the I2C bus. To issue the I2C commands, the emulator should connect to a PC over the USB port. After initializing the emulator, the PC and directly control the I2C slave chip/module. 6 | 7 | This emulator is based on [ATmega16A](https://www.microchip.com/wwwproducts/en/ATmega16A) MCU. The USB communication channel is develop using the [V-USB](https://www.obdev.at/products/vusb/index.html) firmware. 8 | 9 | To simplify the assembly, the PCB of this emulator is designed on a single-side board. The dimensions of the PCB are 96.77mm × 110.73mm. All the parts used in this project are through-hole-type, generally available components. 10 | 11 | This emulator needs an external power supply, and the recommended supply voltage is between 12V - 15V. 12 | 13 | The control software of the emulator is developed using libusb and tested only with *Linux* operating systems. The current firmware and control software support I2C emulation on 100kHz, 250kHz, and 400kHz clock rates. 14 | 15 | Initially, we develop this emulator to work with 5V I2C devices, but later it has extended to work with 3.3V I2C devices. The 3.3V design is still under testing, and at the prototyping stage, we found a couple of issues in 3.3V mode. 16 | 17 | In 3.3V mode, the required output level is available only if the emulator is in a "*ready*" state. In all the other states, it provides 5V output. **Therefore in 3.3V mode, necessary precautions need to be taken to protect the slave device from over-voltage damages.** 18 | 19 | This project is an open-source hardware project. All the content of this project are distributed under the terms of the following license: 20 | 21 | - Hardware License: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) 22 | - Software and firmware License: [MIT](https://github.com/dilshan/i2c-test-terminal/blob/main/LICENSE) 23 | - [Documentation](https://github.com/dilshan/i2c-test-terminal/wiki) License: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) 24 | -------------------------------------------------------------------------------- /design/fp-lib-table: -------------------------------------------------------------------------------- 1 | (fp_lib_table 2 | (lib (name i2c-tester)(type KiCad)(uri ${KIPRJMOD}/i2c-tester.pretty)(options "")(descr "")) 3 | ) 4 | -------------------------------------------------------------------------------- /design/i2c-tester-cache.lib: -------------------------------------------------------------------------------- 1 | EESchema-LIBRARY Version 2.4 2 | #encoding utf-8 3 | # 4 | # Connector_Generic_Conn_01x02 5 | # 6 | DEF Connector_Generic_Conn_01x02 J 0 40 Y N 1 F N 7 | F0 "J" 0 100 50 H V C CNN 8 | F1 "Connector_Generic_Conn_01x02" 0 -200 50 H V C CNN 9 | F2 "" 0 0 50 H I C CNN 10 | F3 "" 0 0 50 H I C CNN 11 | $FPLIST 12 | Connector*:*_1x??_* 13 | $ENDFPLIST 14 | DRAW 15 | S -50 -95 0 -105 1 1 6 N 16 | S -50 5 0 -5 1 1 6 N 17 | S -50 50 50 -150 1 1 10 f 18 | X Pin_1 1 -200 0 150 R 50 50 1 1 P 19 | X Pin_2 2 -200 -100 150 R 50 50 1 1 P 20 | ENDDRAW 21 | ENDDEF 22 | # 23 | # Connector_Generic_Conn_01x04 24 | # 25 | DEF Connector_Generic_Conn_01x04 J 0 40 Y N 1 F N 26 | F0 "J" 0 200 50 H V C CNN 27 | F1 "Connector_Generic_Conn_01x04" 0 -300 50 H V C CNN 28 | F2 "" 0 0 50 H I C CNN 29 | F3 "" 0 0 50 H I C CNN 30 | $FPLIST 31 | Connector*:*_1x??_* 32 | $ENDFPLIST 33 | DRAW 34 | S -50 -195 0 -205 1 1 6 N 35 | S -50 -95 0 -105 1 1 6 N 36 | S -50 5 0 -5 1 1 6 N 37 | S -50 105 0 95 1 1 6 N 38 | S -50 150 50 -250 1 1 10 f 39 | X Pin_1 1 -200 100 150 R 50 50 1 1 P 40 | X Pin_2 2 -200 0 150 R 50 50 1 1 P 41 | X Pin_3 3 -200 -100 150 R 50 50 1 1 P 42 | X Pin_4 4 -200 -200 150 R 50 50 1 1 P 43 | ENDDRAW 44 | ENDDEF 45 | # 46 | # Connector_Generic_Conn_02x05_Odd_Even 47 | # 48 | DEF Connector_Generic_Conn_02x05_Odd_Even J 0 40 Y N 1 F N 49 | F0 "J" 50 300 50 H V C CNN 50 | F1 "Connector_Generic_Conn_02x05_Odd_Even" 50 -300 50 H V C CNN 51 | F2 "" 0 0 50 H I C CNN 52 | F3 "" 0 0 50 H I C CNN 53 | $FPLIST 54 | Connector*:*_2x??_* 55 | $ENDFPLIST 56 | DRAW 57 | S -50 -195 0 -205 1 1 6 N 58 | S -50 -95 0 -105 1 1 6 N 59 | S -50 5 0 -5 1 1 6 N 60 | S -50 105 0 95 1 1 6 N 61 | S -50 205 0 195 1 1 6 N 62 | S -50 250 150 -250 1 1 10 f 63 | S 150 -195 100 -205 1 1 6 N 64 | S 150 -95 100 -105 1 1 6 N 65 | S 150 5 100 -5 1 1 6 N 66 | S 150 105 100 95 1 1 6 N 67 | S 150 205 100 195 1 1 6 N 68 | X Pin_1 1 -200 200 150 R 50 50 1 1 P 69 | X Pin_10 10 300 -200 150 L 50 50 1 1 P 70 | X Pin_2 2 300 200 150 L 50 50 1 1 P 71 | X Pin_3 3 -200 100 150 R 50 50 1 1 P 72 | X Pin_4 4 300 100 150 L 50 50 1 1 P 73 | X Pin_5 5 -200 0 150 R 50 50 1 1 P 74 | X Pin_6 6 300 0 150 L 50 50 1 1 P 75 | X Pin_7 7 -200 -100 150 R 50 50 1 1 P 76 | X Pin_8 8 300 -100 150 L 50 50 1 1 P 77 | X Pin_9 9 -200 -200 150 R 50 50 1 1 P 78 | ENDDRAW 79 | ENDDEF 80 | # 81 | # Connector_USB_B 82 | # 83 | DEF Connector_USB_B J 0 40 Y Y 1 F N 84 | F0 "J" -200 450 50 H V L CNN 85 | F1 "Connector_USB_B" -200 350 50 H V L CNN 86 | F2 "" 150 -50 50 H I C CNN 87 | F3 "" 150 -50 50 H I C CNN 88 | $FPLIST 89 | USB* 90 | $ENDFPLIST 91 | DRAW 92 | C -150 85 25 0 1 10 F 93 | C -25 135 15 0 1 10 F 94 | S -200 -300 200 300 0 1 10 f 95 | S -150 220 -100 180 0 1 0 F 96 | S -5 -300 5 -270 0 1 0 N 97 | S 10 50 -20 20 0 1 10 F 98 | S 200 -105 170 -95 0 1 0 N 99 | S 200 -5 170 5 0 1 0 N 100 | S 200 195 170 205 0 1 0 N 101 | P 2 0 1 10 -75 85 25 85 N 102 | P 4 0 1 10 -125 85 -100 85 -50 135 -25 135 N 103 | P 4 0 1 10 -100 85 -75 85 -50 35 0 35 N 104 | P 4 0 1 10 25 110 25 60 75 85 25 110 F 105 | P 7 0 1 0 -160 170 -90 170 -90 225 -105 240 -145 240 -160 225 -160 170 N 106 | X VBUS 1 300 200 100 L 50 50 1 1 w 107 | X D- 2 300 -100 100 L 50 50 1 1 B 108 | X D+ 3 300 0 100 L 50 50 1 1 B 109 | X GND 4 0 -400 100 U 50 50 1 1 w 110 | X Shield 5 -100 -400 100 U 50 50 1 1 P 111 | ENDDRAW 112 | ENDDEF 113 | # 114 | # Device_C 115 | # 116 | DEF Device_C C 0 10 N Y 1 F N 117 | F0 "C" 25 100 50 H V L CNN 118 | F1 "Device_C" 25 -100 50 H V L CNN 119 | F2 "" 38 -150 50 H I C CNN 120 | F3 "" 0 0 50 H I C CNN 121 | $FPLIST 122 | C_* 123 | $ENDFPLIST 124 | DRAW 125 | P 2 0 1 20 -80 -30 80 -30 N 126 | P 2 0 1 20 -80 30 80 30 N 127 | X ~ 1 0 150 110 D 50 50 1 1 P 128 | X ~ 2 0 -150 110 U 50 50 1 1 P 129 | ENDDRAW 130 | ENDDEF 131 | # 132 | # Device_CP1 133 | # 134 | DEF Device_CP1 C 0 10 N N 1 F N 135 | F0 "C" 25 100 50 H V L CNN 136 | F1 "Device_CP1" 25 -100 50 H V L CNN 137 | F2 "" 0 0 50 H I C CNN 138 | F3 "" 0 0 50 H I C CNN 139 | $FPLIST 140 | CP_* 141 | $ENDFPLIST 142 | DRAW 143 | A 0 -150 128 1287 513 0 1 20 N -80 -50 80 -50 144 | P 2 0 1 20 -80 30 80 30 N 145 | P 2 0 1 0 -70 90 -30 90 N 146 | P 2 0 1 0 -50 70 -50 110 N 147 | X ~ 1 0 150 110 D 50 50 1 1 P 148 | X ~ 2 0 -150 130 U 50 50 1 1 P 149 | ENDDRAW 150 | ENDDEF 151 | # 152 | # Device_Crystal 153 | # 154 | DEF Device_Crystal Y 0 40 N N 1 F N 155 | F0 "Y" 0 150 50 H V C CNN 156 | F1 "Device_Crystal" 0 -150 50 H V C CNN 157 | F2 "" 0 0 50 H I C CNN 158 | F3 "" 0 0 50 H I C CNN 159 | $FPLIST 160 | Crystal* 161 | $ENDFPLIST 162 | DRAW 163 | S -45 100 45 -100 0 1 12 N 164 | P 2 0 1 0 -100 0 -75 0 N 165 | P 2 0 1 20 -75 -50 -75 50 N 166 | P 2 0 1 20 75 -50 75 50 N 167 | P 2 0 1 0 100 0 75 0 N 168 | X 1 1 -150 0 50 R 50 50 1 1 P 169 | X 2 2 150 0 50 L 50 50 1 1 P 170 | ENDDRAW 171 | ENDDEF 172 | # 173 | # Device_D 174 | # 175 | DEF Device_D D 0 40 N N 1 F N 176 | F0 "D" 0 100 50 H V C CNN 177 | F1 "Device_D" 0 -100 50 H V C CNN 178 | F2 "" 0 0 50 H I C CNN 179 | F3 "" 0 0 50 H I C CNN 180 | $FPLIST 181 | TO-???* 182 | *_Diode_* 183 | *SingleDiode* 184 | D_* 185 | $ENDFPLIST 186 | DRAW 187 | P 2 0 1 10 -50 50 -50 -50 N 188 | P 2 0 1 0 50 0 -50 0 N 189 | P 4 0 1 10 50 50 50 -50 -50 0 50 50 N 190 | X K 1 -150 0 100 R 50 50 1 1 P 191 | X A 2 150 0 100 L 50 50 1 1 P 192 | ENDDRAW 193 | ENDDEF 194 | # 195 | # Device_D_Schottky 196 | # 197 | DEF Device_D_Schottky D 0 40 N N 1 F N 198 | F0 "D" 0 100 50 H V C CNN 199 | F1 "Device_D_Schottky" 0 -100 50 H V C CNN 200 | F2 "" 0 0 50 H I C CNN 201 | F3 "" 0 0 50 H I C CNN 202 | $FPLIST 203 | TO-???* 204 | *_Diode_* 205 | *SingleDiode* 206 | D_* 207 | $ENDFPLIST 208 | DRAW 209 | P 2 0 1 0 50 0 -50 0 N 210 | P 4 0 1 10 50 50 50 -50 -50 0 50 50 N 211 | P 6 0 1 10 -75 25 -75 50 -50 50 -50 -50 -25 -50 -25 -25 N 212 | X K 1 -150 0 100 R 50 50 1 1 P 213 | X A 2 150 0 100 L 50 50 1 1 P 214 | ENDDRAW 215 | ENDDEF 216 | # 217 | # Device_D_Zener 218 | # 219 | DEF Device_D_Zener D 0 40 N N 1 F N 220 | F0 "D" 0 100 50 H V C CNN 221 | F1 "Device_D_Zener" 0 -100 50 H V C CNN 222 | F2 "" 0 0 50 H I C CNN 223 | F3 "" 0 0 50 H I C CNN 224 | $FPLIST 225 | TO-???* 226 | *_Diode_* 227 | *SingleDiode* 228 | D_* 229 | $ENDFPLIST 230 | DRAW 231 | P 2 0 1 0 50 0 -50 0 N 232 | P 3 0 1 10 -50 -50 -50 50 -30 50 N 233 | P 4 0 1 10 50 -50 50 50 -50 0 50 -50 N 234 | X K 1 -150 0 100 R 50 50 1 1 P 235 | X A 2 150 0 100 L 50 50 1 1 P 236 | ENDDRAW 237 | ENDDEF 238 | # 239 | # Device_Ferrite_Bead 240 | # 241 | DEF Device_Ferrite_Bead FB 0 0 N Y 1 F N 242 | F0 "FB" -150 25 50 V V C CNN 243 | F1 "Device_Ferrite_Bead" 150 0 50 V V C CNN 244 | F2 "" -70 0 50 V I C CNN 245 | F3 "" 0 0 50 H I C CNN 246 | $FPLIST 247 | Inductor_* 248 | L_* 249 | *Ferrite* 250 | $ENDFPLIST 251 | DRAW 252 | P 2 0 1 0 0 -50 0 -48 N 253 | P 2 0 1 0 0 50 0 51 N 254 | P 5 0 1 0 -109 16 -67 89 109 -12 66 -85 -109 16 N 255 | X ~ 1 0 150 100 D 50 50 1 1 P 256 | X ~ 2 0 -150 100 U 50 50 1 1 P 257 | ENDDRAW 258 | ENDDEF 259 | # 260 | # Device_Polyfuse 261 | # 262 | DEF Device_Polyfuse F 0 0 N Y 1 F N 263 | F0 "F" -100 0 50 V V C CNN 264 | F1 "Device_Polyfuse" 100 0 50 V V C CNN 265 | F2 "" 50 -200 50 H I L CNN 266 | F3 "" 0 0 50 H I C CNN 267 | $FPLIST 268 | *polyfuse* 269 | *PTC* 270 | $ENDFPLIST 271 | DRAW 272 | S -30 100 30 -100 0 1 10 N 273 | P 2 0 1 0 0 100 0 -100 N 274 | P 4 0 1 0 -60 100 -60 60 60 -60 60 -100 N 275 | X ~ 1 0 150 50 D 50 50 1 1 P 276 | X ~ 2 0 -150 50 U 50 50 1 1 P 277 | ENDDRAW 278 | ENDDEF 279 | # 280 | # Device_Q_NPN_ECB 281 | # 282 | DEF Device_Q_NPN_ECB Q 0 0 Y N 1 F N 283 | F0 "Q" 200 50 50 H V L CNN 284 | F1 "Device_Q_NPN_ECB" 200 -50 50 H V L CNN 285 | F2 "" 200 100 50 H I C CNN 286 | F3 "" 0 0 50 H I C CNN 287 | DRAW 288 | C 50 0 111 0 1 10 N 289 | P 2 0 1 0 25 25 100 100 N 290 | P 3 0 1 0 25 -25 100 -100 100 -100 N 291 | P 3 0 1 20 25 75 25 -75 25 -75 N 292 | P 5 0 1 0 50 -70 70 -50 90 -90 50 -70 50 -70 F 293 | X E 1 100 -200 100 U 50 50 1 1 P 294 | X C 2 100 200 100 D 50 50 1 1 P 295 | X B 3 -200 0 225 R 50 50 1 1 P 296 | ENDDRAW 297 | ENDDEF 298 | # 299 | # Device_R 300 | # 301 | DEF Device_R R 0 0 N Y 1 F N 302 | F0 "R" 80 0 50 V V C CNN 303 | F1 "Device_R" 0 0 50 V V C CNN 304 | F2 "" -70 0 50 V I C CNN 305 | F3 "" 0 0 50 H I C CNN 306 | $FPLIST 307 | R_* 308 | $ENDFPLIST 309 | DRAW 310 | S -40 -100 40 100 0 1 10 N 311 | X ~ 1 0 150 50 D 50 50 1 1 P 312 | X ~ 2 0 -150 50 U 50 50 1 1 P 313 | ENDDRAW 314 | ENDDEF 315 | # 316 | # Diode_1N4001 317 | # 318 | DEF Diode_1N4001 D 0 40 N N 1 F N 319 | F0 "D" 0 100 50 H V C CNN 320 | F1 "Diode_1N4001" 0 -100 50 H V C CNN 321 | F2 "Diode_THT:D_DO-41_SOD81_P10.16mm_Horizontal" 0 -175 50 H I C CNN 322 | F3 "" 0 0 50 H I C CNN 323 | ALIAS 1N4002 1N4003 1N4004 1N4005 1N4006 1N4007 BA157 BA158 BA159 324 | $FPLIST 325 | D*DO?41* 326 | $ENDFPLIST 327 | DRAW 328 | P 2 0 1 10 -50 50 -50 -50 N 329 | P 2 0 1 0 50 0 -50 0 N 330 | P 4 0 1 10 50 50 50 -50 -50 0 50 50 N 331 | X K 1 -150 0 100 R 50 50 1 1 P 332 | X A 2 150 0 100 L 50 50 1 1 P 333 | ENDDRAW 334 | ENDDEF 335 | # 336 | # MCU_Microchip_ATmega_ATmega16A-PU 337 | # 338 | DEF MCU_Microchip_ATmega_ATmega16A-PU U 0 20 Y Y 1 F N 339 | F0 "U" -500 1950 50 H V L BNN 340 | F1 "MCU_Microchip_ATmega_ATmega16A-PU" 100 -1950 50 H V L TNN 341 | F2 "Package_DIP:DIP-40_W15.24mm" 0 0 50 H I C CIN 342 | F3 "" 0 0 50 H I C CNN 343 | ALIAS ATmega16-16PU ATmega16A-PU ATmega32L-8PU ATmega32-16PU ATmega32A-PU 344 | $FPLIST 345 | DIP*W15.24mm* 346 | $ENDFPLIST 347 | DRAW 348 | S -500 -1900 500 1900 0 1 10 f 349 | X PB0 1 600 800 100 L 50 50 1 1 B 350 | X VCC 10 0 2000 100 D 50 50 1 1 W 351 | X GND 11 0 -2000 100 U 50 50 1 1 W 352 | X XTAL2 12 -600 1300 100 R 50 50 1 1 O 353 | X XTAL1 13 -600 1500 100 R 50 50 1 1 I 354 | X PD0 14 600 -1000 100 L 50 50 1 1 B 355 | X PD1 15 600 -1100 100 L 50 50 1 1 B 356 | X PD2 16 600 -1200 100 L 50 50 1 1 B 357 | X PD3 17 600 -1300 100 L 50 50 1 1 B 358 | X PD4 18 600 -1400 100 L 50 50 1 1 B 359 | X PD5 19 600 -1500 100 L 50 50 1 1 B 360 | X PB1 2 600 700 100 L 50 50 1 1 B 361 | X PD6 20 600 -1600 100 L 50 50 1 1 B 362 | X PD7 21 600 -1700 100 L 50 50 1 1 B 363 | X PC0 22 600 -100 100 L 50 50 1 1 B 364 | X PC1 23 600 -200 100 L 50 50 1 1 B 365 | X PC2 24 600 -300 100 L 50 50 1 1 B 366 | X PC3 25 600 -400 100 L 50 50 1 1 B 367 | X PC4 26 600 -500 100 L 50 50 1 1 B 368 | X PC5 27 600 -600 100 L 50 50 1 1 B 369 | X PC6 28 600 -700 100 L 50 50 1 1 B 370 | X PC7 29 600 -800 100 L 50 50 1 1 B 371 | X PB2 3 600 600 100 L 50 50 1 1 B 372 | X AVCC 30 100 2000 100 D 50 50 1 1 W 373 | X GND 31 0 -2000 100 U 50 50 1 1 P N 374 | X AREF 32 -600 1100 100 R 50 50 1 1 P 375 | X PA7 33 600 1000 100 L 50 50 1 1 B 376 | X PA6 34 600 1100 100 L 50 50 1 1 B 377 | X PA5 35 600 1200 100 L 50 50 1 1 B 378 | X PA4 36 600 1300 100 L 50 50 1 1 B 379 | X PA3 37 600 1400 100 L 50 50 1 1 B 380 | X PA2 38 600 1500 100 L 50 50 1 1 B 381 | X PA1 39 600 1600 100 L 50 50 1 1 B 382 | X PB3 4 600 500 100 L 50 50 1 1 B 383 | X PA0 40 600 1700 100 L 50 50 1 1 B 384 | X PB4 5 600 400 100 L 50 50 1 1 B 385 | X PB5 6 600 300 100 L 50 50 1 1 B 386 | X PB6 7 600 200 100 L 50 50 1 1 B 387 | X PB7 8 600 100 100 L 50 50 1 1 B 388 | X ~RESET 9 -600 1700 100 R 50 50 1 1 I 389 | ENDDRAW 390 | ENDDEF 391 | # 392 | # Regulator_Linear_AZ1117-3.3 393 | # 394 | DEF Regulator_Linear_AZ1117-3.3 U 0 10 Y Y 1 F N 395 | F0 "U" -150 125 50 H V C CNN 396 | F1 "Regulator_Linear_AZ1117-3.3" 0 125 50 H V L CNN 397 | F2 "" 0 250 50 H I C CIN 398 | F3 "" 0 0 50 H I C CNN 399 | ALIAS AZ1117-1.5 AZ1117-1.8 AZ1117-2.5 AZ1117-2.85 AZ1117-3.3 AZ1117-5.0 400 | $FPLIST 401 | SOT?223* 402 | SOT?89* 403 | TO?220* 404 | TO?252* 405 | TO?263* 406 | $ENDFPLIST 407 | DRAW 408 | S -200 75 200 -200 0 1 10 f 409 | X GND 1 0 -300 100 U 50 50 1 1 W 410 | X VO 2 300 0 100 L 50 50 1 1 w 411 | X VI 3 -300 0 100 R 50 50 1 1 W 412 | ENDDRAW 413 | ENDDEF 414 | # 415 | # Regulator_Switching_LM2596T-5 416 | # 417 | DEF Regulator_Switching_LM2596T-5 U 0 20 Y Y 1 F N 418 | F0 "U" -400 250 50 H V L CNN 419 | F1 "Regulator_Switching_LM2596T-5" 0 250 50 H V L CNN 420 | F2 "Package_TO_SOT_THT:TO-220-5_P3.4x3.7mm_StaggerOdd_Lead3.8mm_Vertical" 50 -250 50 H I L CIN 421 | F3 "" 0 0 50 H I C CNN 422 | ALIAS LM2596T-5 LM2596T-3.3 LM2596T-ADJ 423 | $FPLIST 424 | TO?220* 425 | $ENDFPLIST 426 | DRAW 427 | S -400 200 400 -200 0 1 10 f 428 | X VIN 1 -500 100 100 R 50 50 1 1 W 429 | X OUT 2 500 -100 100 L 50 50 1 1 O 430 | X GND 3 0 -300 100 U 50 50 1 1 W 431 | X FB 4 500 100 100 L 50 50 1 1 I 432 | X ~ON~/OFF 5 -500 -100 100 R 50 50 1 1 I 433 | ENDDRAW 434 | ENDDEF 435 | # 436 | # Relay_EC2-5NU 437 | # 438 | DEF Relay_EC2-5NU K 0 20 Y Y 1 F N 439 | F0 "K" 600 350 50 H V C CNN 440 | F1 "Relay_EC2-5NU" 750 250 50 H V C CNN 441 | F2 "Relay_THT:Relay_DPDT_Kemet_EC2" 0 0 50 H I C CNN 442 | F3 "" 0 0 50 H I C CNN 443 | ALIAS EC2-4.5NU EC2-5NU EC2-12NU EC2-24NU 444 | $FPLIST 445 | Relay*THT*Kemet*EC2* 446 | $ENDFPLIST 447 | DRAW 448 | T 0 -365 115 50 0 1 1 + Normal 0 C C 449 | S -600 200 600 -200 1 1 10 f 450 | S -525 75 -275 -75 1 1 10 N 451 | P 2 1 1 10 -500 -75 -300 75 N 452 | P 2 1 1 0 -400 -200 -400 -75 N 453 | P 2 1 1 0 -400 200 -400 75 N 454 | P 2 1 1 10 -275 0 -250 0 N 455 | P 2 1 1 10 -225 0 -200 0 N 456 | P 2 1 1 10 -175 0 -150 0 N 457 | P 2 1 1 10 -125 0 -100 0 N 458 | P 2 1 1 10 -75 0 -50 0 N 459 | P 2 1 1 10 -25 0 0 0 N 460 | P 2 1 1 20 0 -100 -75 150 N 461 | P 2 1 1 0 0 -100 0 -200 N 462 | P 2 1 1 10 25 0 50 0 N 463 | P 2 1 1 10 75 0 100 0 N 464 | P 2 1 1 10 125 0 150 0 N 465 | P 2 1 1 10 175 0 200 0 N 466 | P 2 1 1 10 225 0 250 0 N 467 | P 2 1 1 10 275 0 300 0 N 468 | P 2 1 1 10 325 0 350 0 N 469 | P 2 1 1 20 400 -100 325 150 N 470 | P 2 1 1 0 400 -100 400 -200 N 471 | P 4 1 1 0 -100 200 -100 100 -75 125 -100 150 F 472 | P 4 1 1 0 100 200 100 100 75 125 100 150 N 473 | P 4 1 1 0 300 200 300 100 325 125 300 150 F 474 | P 4 1 1 0 500 200 500 100 475 125 500 150 N 475 | X ~ 1 -400 300 100 D 50 50 1 1 P 476 | X ~ 10 300 300 100 D 50 50 1 1 P 477 | X ~ 12 -400 -300 100 U 50 50 1 1 P 478 | X ~ 3 -100 300 100 D 50 50 1 1 P 479 | X ~ 4 0 -300 100 U 50 50 1 1 P 480 | X ~ 5 100 300 100 D 50 50 1 1 P 481 | X ~ 8 500 300 100 D 50 50 1 1 P 482 | X ~ 9 400 -300 100 U 50 50 1 1 P 483 | ENDDRAW 484 | ENDDEF 485 | # 486 | # Transistor_FET_2N7000 487 | # 488 | DEF Transistor_FET_2N7000 Q 0 20 Y N 1 F N 489 | F0 "Q" 200 75 50 H V L CNN 490 | F1 "Transistor_FET_2N7000" 200 0 50 H V L CNN 491 | F2 "Package_TO_SOT_THT:TO-92_Inline" 200 -75 50 H I L CIN 492 | F3 "" 0 0 50 H I L CNN 493 | $FPLIST 494 | TO?92* 495 | $ENDFPLIST 496 | DRAW 497 | C 65 0 110 0 1 10 N 498 | C 100 -70 10 0 1 0 F 499 | C 100 70 10 0 1 0 F 500 | P 2 0 1 0 10 0 -100 0 N 501 | P 2 0 1 10 10 75 10 -75 N 502 | P 2 0 1 10 30 -50 30 -90 N 503 | P 2 0 1 10 30 20 30 -20 N 504 | P 2 0 1 10 30 90 30 50 N 505 | P 2 0 1 0 100 100 100 70 N 506 | P 3 0 1 0 100 -100 100 0 30 0 N 507 | P 4 0 1 0 30 -70 130 -70 130 70 30 70 N 508 | P 4 0 1 0 40 0 80 15 80 -15 40 0 F 509 | P 4 0 1 0 110 20 115 15 145 15 150 10 N 510 | P 4 0 1 0 130 15 115 -10 145 -10 130 15 N 511 | X S 1 100 -200 100 U 50 50 1 1 P 512 | X G 2 -200 0 100 R 50 50 1 1 I 513 | X D 3 100 200 100 D 50 50 1 1 P 514 | ENDDRAW 515 | ENDDEF 516 | # 517 | # power_+3.3V 518 | # 519 | DEF power_+3.3V #PWR 0 0 Y Y 1 F P 520 | F0 "#PWR" 0 -150 50 H I C CNN 521 | F1 "power_+3.3V" 0 140 50 H V C CNN 522 | F2 "" 0 0 50 H I C CNN 523 | F3 "" 0 0 50 H I C CNN 524 | ALIAS +3.3V 525 | DRAW 526 | P 2 0 1 0 -30 50 0 100 N 527 | P 2 0 1 0 0 0 0 100 N 528 | P 2 0 1 0 0 100 30 50 N 529 | X +3V3 1 0 0 0 U 50 50 1 1 W N 530 | ENDDRAW 531 | ENDDEF 532 | # 533 | # power_+5V 534 | # 535 | DEF power_+5V #PWR 0 0 Y Y 1 F P 536 | F0 "#PWR" 0 -150 50 H I C CNN 537 | F1 "power_+5V" 0 140 50 H V C CNN 538 | F2 "" 0 0 50 H I C CNN 539 | F3 "" 0 0 50 H I C CNN 540 | DRAW 541 | P 2 0 1 0 -30 50 0 100 N 542 | P 2 0 1 0 0 0 0 100 N 543 | P 2 0 1 0 0 100 30 50 N 544 | X +5V 1 0 0 0 U 50 50 1 1 W N 545 | ENDDRAW 546 | ENDDEF 547 | # 548 | # power_GND 549 | # 550 | DEF power_GND #PWR 0 0 Y Y 1 F P 551 | F0 "#PWR" 0 -250 50 H I C CNN 552 | F1 "power_GND" 0 -150 50 H V C CNN 553 | F2 "" 0 0 50 H I C CNN 554 | F3 "" 0 0 50 H I C CNN 555 | DRAW 556 | P 6 0 1 0 0 0 0 -50 50 -50 0 -100 -50 -50 0 -50 N 557 | X GND 1 0 0 0 D 50 50 1 1 W N 558 | ENDDRAW 559 | ENDDEF 560 | # 561 | # power_PWR_FLAG 562 | # 563 | DEF power_PWR_FLAG #FLG 0 0 N N 1 F P 564 | F0 "#FLG" 0 75 50 H I C CNN 565 | F1 "power_PWR_FLAG" 0 150 50 H V C CNN 566 | F2 "" 0 0 50 H I C CNN 567 | F3 "" 0 0 50 H I C CNN 568 | DRAW 569 | P 6 0 1 0 0 0 0 50 -40 75 0 100 40 75 0 50 N 570 | X pwr 1 0 0 0 U 50 50 0 0 w 571 | ENDDRAW 572 | ENDDEF 573 | # 574 | # pspice_INDUCTOR 575 | # 576 | DEF pspice_INDUCTOR L 0 0 N Y 1 F N 577 | F0 "L" 0 100 50 H V C CNN 578 | F1 "pspice_INDUCTOR" 0 -50 50 H V C CNN 579 | F2 "" 0 0 50 H I C CNN 580 | F3 "" 0 0 50 H I C CNN 581 | DRAW 582 | A -150 0 50 1 1799 0 1 0 N -100 0 -200 0 583 | A -50 0 50 1 1799 0 1 0 N 0 0 -100 0 584 | A 50 0 50 1 1799 0 1 0 N 100 0 0 0 585 | A 150 0 50 1 1799 0 1 0 N 200 0 100 0 586 | X 1 1 -250 0 50 R 30 30 1 1 I 587 | X 2 2 250 0 50 L 30 30 1 1 I 588 | ENDDRAW 589 | ENDDEF 590 | # 591 | #End Library 592 | -------------------------------------------------------------------------------- /design/i2c-tester.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dilshan/i2c-test-terminal/7def072ba9c85831d2352408248afc9305152494/design/i2c-tester.pdf -------------------------------------------------------------------------------- /design/i2c-tester.pretty/enclosure-i2c-tester.kicad_mod: -------------------------------------------------------------------------------- 1 | (module enclosure-i2c-tester (layer F.Cu) (tedit 5FF5678F) 2 | (fp_text reference REF** (at 1.9 -1.6) (layer F.SilkS) 3 | (effects (font (size 1 1) (thickness 0.15))) 4 | ) 5 | (fp_text value enclosure-i2c-tester (at 104.9 152.4) (layer F.Fab) 6 | (effects (font (size 1 1) (thickness 0.15))) 7 | ) 8 | (fp_circle (center 13 33.5) (end 15.5 33.5) (layer Eco2.User) (width 0.12)) 9 | (fp_circle (center 42 33.5) (end 44.5 33.5) (layer Eco2.User) (width 0.12)) 10 | (fp_circle (center 71 33.5) (end 73.5 33.5) (layer Eco2.User) (width 0.12)) 11 | (fp_circle (center 100 33.5) (end 102.5 33.5) (layer Eco2.User) (width 0.12)) 12 | (fp_line (start 0 0) (end 0 150.7) (layer Eco2.User) (width 0.12)) 13 | (fp_line (start 0 150.7) (end 113 150.7) (layer Eco2.User) (width 0.12)) 14 | (fp_line (start 113 150.7) (end 113 0) (layer Eco2.User) (width 0.12)) 15 | (fp_line (start 113 0) (end 0 0) (layer Eco2.User) (width 0.12)) 16 | (fp_line (start 6.5 2.5) (end 106.5 2.5) (layer Eco2.User) (width 0.12)) 17 | (fp_line (start 6.5 148.2) (end 106.5 148.2) (layer Eco2.User) (width 0.12)) 18 | (fp_line (start 106.5 0) (end 106.5 150.7) (layer Eco2.User) (width 0.12)) 19 | (fp_line (start 6.5 0) (end 6.5 150.7) (layer Eco2.User) (width 0.12)) 20 | (fp_line (start 3 0) (end 3 150.7) (layer Eco2.User) (width 0.12)) 21 | (fp_line (start 110 0) (end 110 150.7) (layer Eco2.User) (width 0.12)) 22 | (fp_line (start 5 0) (end 5 150.7) (layer Eco2.User) (width 0.12)) 23 | (fp_line (start 108 0) (end 108 150.7) (layer Eco2.User) (width 0.12)) 24 | (fp_line (start 102 0) (end 102 150.7) (layer Eco1.User) (width 0.12)) 25 | (fp_line (start 113 7.5) (end 0 7.5) (layer Eco1.User) (width 0.12)) 26 | (fp_line (start 113 143.2) (end 0 143.2) (layer Eco1.User) (width 0.12)) 27 | (fp_line (start 22 0) (end 22 150.7) (layer Eco1.User) (width 0.12)) 28 | (fp_line (start 91 0) (end 91 150.7) (layer Eco1.User) (width 0.12)) 29 | (fp_circle (center 91 7.5) (end 94.2 7.4) (layer Eco2.User) (width 0.12)) 30 | (fp_circle (center 102 7.5) (end 105.2 7.4) (layer Eco2.User) (width 0.12)) 31 | (fp_circle (center 22.001562 7.5) (end 25.201562 7.4) (layer Eco2.User) (width 0.12)) 32 | (fp_circle (center 22 143.2) (end 25.2 143.1) (layer Eco2.User) (width 0.12)) 33 | (fp_circle (center 102 143.201562) (end 105.2 143.101562) (layer Eco2.User) (width 0.12)) 34 | (fp_circle (center 91 143.201562) (end 94.2 143.101562) (layer Eco2.User) (width 0.12)) 35 | (fp_line (start 113 33.5) (end 6.5 33.5) (layer Eco1.User) (width 0.12)) 36 | (fp_line (start 113 117.2) (end 6.5 117.2) (layer Eco1.User) (width 0.12)) 37 | (fp_line (start 13 0) (end 13 150.7) (layer Eco1.User) (width 0.12)) 38 | (fp_line (start 100 0) (end 100 150.7) (layer Eco1.User) (width 0.12)) 39 | (fp_line (start 71 28.1) (end 71 123) (layer Eco1.User) (width 0.12)) 40 | (fp_line (start 42 28.1) (end 42 123) (layer Eco1.User) (width 0.12)) 41 | (fp_line (start 13 33.5) (end 13 117.2) (layer Eco1.User) (width 0.12)) 42 | (fp_circle (center 13 117.2) (end 15.5 117.2) (layer Eco2.User) (width 0.12)) 43 | (fp_circle (center 42 117.2) (end 44.5 117.2) (layer Eco2.User) (width 0.12)) 44 | (fp_circle (center 71 117.2) (end 73.5 117.2) (layer Eco2.User) (width 0.12)) 45 | (fp_circle (center 91 117.2) (end 93.5 117.2) (layer Eco2.User) (width 0.12)) 46 | (fp_text user FRONT (at 107.9 -1.7) (layer Eco2.User) 47 | (effects (font (size 2 2) (thickness 0.15))) 48 | ) 49 | (fp_text user BACK (at 3.4 152.9) (layer Eco2.User) 50 | (effects (font (size 2 2) (thickness 0.15))) 51 | ) 52 | ) 53 | -------------------------------------------------------------------------------- /design/i2c-tester.pro: -------------------------------------------------------------------------------- 1 | update=Tue 16 Mar 2021 12:40:30 PM +0530 2 | version=1 3 | last_client=kicad 4 | [general] 5 | version=1 6 | RootSch= 7 | BoardNm= 8 | [cvpcb] 9 | version=1 10 | NetIExt=net 11 | [eeschema] 12 | version=1 13 | LibDir= 14 | [eeschema/libraries] 15 | [pcbnew] 16 | version=1 17 | PageLayoutDescrFile= 18 | LastNetListRead=i2c-tester.net 19 | CopperLayerCount=2 20 | BoardThickness=1.6 21 | AllowMicroVias=0 22 | AllowBlindVias=0 23 | RequireCourtyardDefinitions=0 24 | ProhibitOverlappingCourtyards=1 25 | MinTrackWidth=0.2 26 | MinViaDiameter=0.4 27 | MinViaDrill=0.3 28 | MinMicroViaDiameter=0.2 29 | MinMicroViaDrill=0.09999999999999999 30 | MinHoleToHole=0.25 31 | TrackWidth1=0.25 32 | TrackWidth2=0.25 33 | TrackWidth3=0.35 34 | TrackWidth4=0.45 35 | TrackWidth5=0.5 36 | TrackWidth6=0.6 37 | TrackWidth7=0.75 38 | TrackWidth8=1 39 | TrackWidth9=1.4 40 | ViaDiameter1=0.8 41 | ViaDrill1=0.4 42 | dPairWidth1=0.2 43 | dPairGap1=0.25 44 | dPairViaGap1=0.25 45 | SilkLineWidth=0.12 46 | SilkTextSizeV=1 47 | SilkTextSizeH=1 48 | SilkTextSizeThickness=0.15 49 | SilkTextItalic=0 50 | SilkTextUpright=1 51 | CopperLineWidth=0.2 52 | CopperTextSizeV=1.5 53 | CopperTextSizeH=1.5 54 | CopperTextThickness=0.3 55 | CopperTextItalic=0 56 | CopperTextUpright=1 57 | EdgeCutLineWidth=0.05 58 | CourtyardLineWidth=0.05 59 | OthersLineWidth=0.15 60 | OthersTextSizeV=1 61 | OthersTextSizeH=1 62 | OthersTextSizeThickness=0.15 63 | OthersTextItalic=0 64 | OthersTextUpright=1 65 | SolderMaskClearance=0 66 | SolderMaskMinWidth=0 67 | SolderPasteClearance=0 68 | SolderPasteRatio=-0 69 | [pcbnew/Layer.F.Cu] 70 | Name=F.Cu 71 | Type=0 72 | Enabled=1 73 | [pcbnew/Layer.In1.Cu] 74 | Name=In1.Cu 75 | Type=0 76 | Enabled=0 77 | [pcbnew/Layer.In2.Cu] 78 | Name=In2.Cu 79 | Type=0 80 | Enabled=0 81 | [pcbnew/Layer.In3.Cu] 82 | Name=In3.Cu 83 | Type=0 84 | Enabled=0 85 | [pcbnew/Layer.In4.Cu] 86 | Name=In4.Cu 87 | Type=0 88 | Enabled=0 89 | [pcbnew/Layer.In5.Cu] 90 | Name=In5.Cu 91 | Type=0 92 | Enabled=0 93 | [pcbnew/Layer.In6.Cu] 94 | Name=In6.Cu 95 | Type=0 96 | Enabled=0 97 | [pcbnew/Layer.In7.Cu] 98 | Name=In7.Cu 99 | Type=0 100 | Enabled=0 101 | [pcbnew/Layer.In8.Cu] 102 | Name=In8.Cu 103 | Type=0 104 | Enabled=0 105 | [pcbnew/Layer.In9.Cu] 106 | Name=In9.Cu 107 | Type=0 108 | Enabled=0 109 | [pcbnew/Layer.In10.Cu] 110 | Name=In10.Cu 111 | Type=0 112 | Enabled=0 113 | [pcbnew/Layer.In11.Cu] 114 | Name=In11.Cu 115 | Type=0 116 | Enabled=0 117 | [pcbnew/Layer.In12.Cu] 118 | Name=In12.Cu 119 | Type=0 120 | Enabled=0 121 | [pcbnew/Layer.In13.Cu] 122 | Name=In13.Cu 123 | Type=0 124 | Enabled=0 125 | [pcbnew/Layer.In14.Cu] 126 | Name=In14.Cu 127 | Type=0 128 | Enabled=0 129 | [pcbnew/Layer.In15.Cu] 130 | Name=In15.Cu 131 | Type=0 132 | Enabled=0 133 | [pcbnew/Layer.In16.Cu] 134 | Name=In16.Cu 135 | Type=0 136 | Enabled=0 137 | [pcbnew/Layer.In17.Cu] 138 | Name=In17.Cu 139 | Type=0 140 | Enabled=0 141 | [pcbnew/Layer.In18.Cu] 142 | Name=In18.Cu 143 | Type=0 144 | Enabled=0 145 | [pcbnew/Layer.In19.Cu] 146 | Name=In19.Cu 147 | Type=0 148 | Enabled=0 149 | [pcbnew/Layer.In20.Cu] 150 | Name=In20.Cu 151 | Type=0 152 | Enabled=0 153 | [pcbnew/Layer.In21.Cu] 154 | Name=In21.Cu 155 | Type=0 156 | Enabled=0 157 | [pcbnew/Layer.In22.Cu] 158 | Name=In22.Cu 159 | Type=0 160 | Enabled=0 161 | [pcbnew/Layer.In23.Cu] 162 | Name=In23.Cu 163 | Type=0 164 | Enabled=0 165 | [pcbnew/Layer.In24.Cu] 166 | Name=In24.Cu 167 | Type=0 168 | Enabled=0 169 | [pcbnew/Layer.In25.Cu] 170 | Name=In25.Cu 171 | Type=0 172 | Enabled=0 173 | [pcbnew/Layer.In26.Cu] 174 | Name=In26.Cu 175 | Type=0 176 | Enabled=0 177 | [pcbnew/Layer.In27.Cu] 178 | Name=In27.Cu 179 | Type=0 180 | Enabled=0 181 | [pcbnew/Layer.In28.Cu] 182 | Name=In28.Cu 183 | Type=0 184 | Enabled=0 185 | [pcbnew/Layer.In29.Cu] 186 | Name=In29.Cu 187 | Type=0 188 | Enabled=0 189 | [pcbnew/Layer.In30.Cu] 190 | Name=In30.Cu 191 | Type=0 192 | Enabled=0 193 | [pcbnew/Layer.B.Cu] 194 | Name=B.Cu 195 | Type=0 196 | Enabled=1 197 | [pcbnew/Layer.B.Adhes] 198 | Enabled=1 199 | [pcbnew/Layer.F.Adhes] 200 | Enabled=1 201 | [pcbnew/Layer.B.Paste] 202 | Enabled=1 203 | [pcbnew/Layer.F.Paste] 204 | Enabled=1 205 | [pcbnew/Layer.B.SilkS] 206 | Enabled=1 207 | [pcbnew/Layer.F.SilkS] 208 | Enabled=1 209 | [pcbnew/Layer.B.Mask] 210 | Enabled=1 211 | [pcbnew/Layer.F.Mask] 212 | Enabled=1 213 | [pcbnew/Layer.Dwgs.User] 214 | Enabled=1 215 | [pcbnew/Layer.Cmts.User] 216 | Enabled=1 217 | [pcbnew/Layer.Eco1.User] 218 | Enabled=1 219 | [pcbnew/Layer.Eco2.User] 220 | Enabled=1 221 | [pcbnew/Layer.Edge.Cuts] 222 | Enabled=1 223 | [pcbnew/Layer.Margin] 224 | Enabled=1 225 | [pcbnew/Layer.B.CrtYd] 226 | Enabled=1 227 | [pcbnew/Layer.F.CrtYd] 228 | Enabled=1 229 | [pcbnew/Layer.B.Fab] 230 | Enabled=1 231 | [pcbnew/Layer.F.Fab] 232 | Enabled=1 233 | [pcbnew/Layer.Rescue] 234 | Enabled=0 235 | [pcbnew/Netclasses] 236 | [pcbnew/Netclasses/Default] 237 | Name=Default 238 | Clearance=0.2 239 | TrackWidth=0.25 240 | ViaDiameter=0.8 241 | ViaDrill=0.4 242 | uViaDiameter=0.3 243 | uViaDrill=0.1 244 | dPairWidth=0.2 245 | dPairGap=0.25 246 | dPairViaGap=0.25 247 | [schematic_editor] 248 | version=1 249 | PageLayoutDescrFile= 250 | PlotDirectoryName=i2c-tester.pdf 251 | SubpartIdSeparator=0 252 | SubpartFirstId=65 253 | NetFmtName=Pcbnew 254 | SpiceAjustPassiveValues=0 255 | LabSize=50 256 | ERC_TestSimilarLabels=1 257 | -------------------------------------------------------------------------------- /firmware/Makefile: -------------------------------------------------------------------------------- 1 | DEVICE = atmega16a 2 | CLOCK = 16000000 3 | 4 | FUSES = -U lfuse:w:0xfe:m -U hfuse:w:0x99:m 5 | AVRDUDE = avrdude -c usbasp -p m16 6 | 7 | OBJ = usbdrv.o usbdrvasm.o i2cdrv.o i2ctester.o 8 | CFLAGS = -Iusbdrv 9 | COMPILE = avr-gcc -Wall -Os $(CFLAGS) -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) 10 | 11 | all: i2ctester.hex 12 | 13 | .c.o: 14 | $(COMPILE) -c $< -o $@ 15 | 16 | .S.o: 17 | $(COMPILE) -x assembler-with-cpp -c $< -o $@ 18 | 19 | .c.s: 20 | $(COMPILE) -S $< -o $@ 21 | 22 | fuse: 23 | $(AVRDUDE) $(FUSES) 24 | 25 | i2ctester.elf: $(OBJ) 26 | $(COMPILE) -o i2ctester.elf $(OBJ) 27 | 28 | i2ctester.hex: i2ctester.elf 29 | rm -f i2ctester.hex 30 | avr-objcopy -j .text -j .data -O ihex i2ctester.elf i2ctester.hex 31 | 32 | flash: all 33 | $(AVRDUDE) -U flash:w:i2ctester.hex:i 34 | 35 | clean: 36 | rm -f i2ctester.hex i2ctester.elf $(OBJ) -------------------------------------------------------------------------------- /firmware/V-USB-CommercialLicense.txt: -------------------------------------------------------------------------------- 1 | V-USB Driver Software License Agreement 2 | Version 2012-07-09 3 | 4 | THIS LICENSE AGREEMENT GRANTS YOU CERTAIN RIGHTS IN A SOFTWARE. YOU CAN 5 | ENTER INTO THIS AGREEMENT AND ACQUIRE THE RIGHTS OUTLINED BELOW BY PAYING 6 | THE AMOUNT ACCORDING TO SECTION 4 ("PAYMENT") TO OBJECTIVE DEVELOPMENT. 7 | 8 | 9 | 1 DEFINITIONS 10 | 11 | 1.1 "OBJECTIVE DEVELOPMENT" shall mean OBJECTIVE DEVELOPMENT Software GmbH, 12 | Grosse Schiffgasse 1A/7, 1020 Wien, AUSTRIA. 13 | 14 | 1.2 "You" shall mean the Licensee. 15 | 16 | 1.3 "V-USB" shall mean all files included in the package distributed under 17 | the name "vusb" by OBJECTIVE DEVELOPMENT (http://www.obdev.at/vusb/) 18 | unless otherwise noted. This includes the firmware-only USB device 19 | implementation for Atmel AVR microcontrollers, some simple device examples 20 | and host side software examples and libraries. 21 | 22 | 23 | 2 LICENSE GRANTS 24 | 25 | 2.1 Source Code. OBJECTIVE DEVELOPMENT shall furnish you with the source 26 | code of V-USB. 27 | 28 | 2.2 Distribution and Use. OBJECTIVE DEVELOPMENT grants you the 29 | non-exclusive right to use, copy and distribute V-USB with your hardware 30 | product(s), restricted by the limitations in section 3 below. 31 | 32 | 2.3 Modifications. OBJECTIVE DEVELOPMENT grants you the right to modify 33 | the source code and your copy of V-USB according to your needs. 34 | 35 | 2.4 USB IDs. OBJECTIVE DEVELOPMENT furnishes you with one or two USB 36 | Product ID(s), sent to you in e-mail. These Product IDs are reserved 37 | exclusively for you. OBJECTIVE DEVELOPMENT has obtained USB Product ID 38 | ranges under the Vendor ID 5824 from Wouter van Ooijen (Van Ooijen 39 | Technische Informatica, www.voti.nl) and under the Vendor ID 8352 from 40 | Jason Kotzin (now flirc.tv, Inc.). Both owners of the Vendor IDs have 41 | obtained these IDs from the USB Implementers Forum, Inc. (www.usb.org). 42 | OBJECTIVE DEVELOPMENT disclaims all liability which might arise from the 43 | assignment of USB IDs. 44 | 45 | 2.5 USB Certification. Although not part of this agreement, we want to make 46 | it clear that you cannot become USB certified when you use V-USB or a USB 47 | Product ID assigned by OBJECTIVE DEVELOPMENT. AVR microcontrollers don't 48 | meet the electrical specifications required by the USB specification and 49 | the USB Implementers Forum certifies only members who bought a Vendor ID of 50 | their own. 51 | 52 | 53 | 3 LICENSE RESTRICTIONS 54 | 55 | 3.1 Number of Units. Only one of the following three definitions is 56 | applicable. Which one is determined by the amount you pay to OBJECTIVE 57 | DEVELOPMENT, see section 4 ("Payment") below. 58 | 59 | Hobby License: You may use V-USB according to section 2 above in no more 60 | than 5 hardware units. These units must not be sold for profit. 61 | 62 | Entry Level License: You may use V-USB according to section 2 above in no 63 | more than 150 hardware units. 64 | 65 | Professional License: You may use V-USB according to section 2 above in 66 | any number of hardware units, except for large scale production ("unlimited 67 | fair use"). Quantities below 10,000 units are not considered large scale 68 | production. If your reach quantities which are obviously large scale 69 | production, you must pay a license fee of 0.10 EUR per unit for all units 70 | above 10,000. 71 | 72 | 3.2 Rental. You may not rent, lease, or lend V-USB or otherwise encumber 73 | any copy of V-USB, or any of the rights granted herein. 74 | 75 | 3.3 Transfer. You may not transfer your rights under this Agreement to 76 | another party without OBJECTIVE DEVELOPMENT's prior written consent. If 77 | such consent is obtained, you may permanently transfer this License to 78 | another party. The recipient of such transfer must agree to all terms and 79 | conditions of this Agreement. 80 | 81 | 3.4 Reservation of Rights. OBJECTIVE DEVELOPMENT retains all rights not 82 | expressly granted. 83 | 84 | 3.5 Non-Exclusive Rights. Your license rights under this Agreement are 85 | non-exclusive. 86 | 87 | 3.6 Third Party Rights. This Agreement cannot grant you rights controlled 88 | by third parties. In particular, you are not allowed to use the USB logo or 89 | other trademarks owned by the USB Implementers Forum, Inc. without their 90 | consent. Since such consent depends on USB certification, it should be 91 | noted that V-USB will not pass certification because it does not 92 | implement checksum verification and the microcontroller ports do not meet 93 | the electrical specifications. 94 | 95 | 96 | 4 PAYMENT 97 | 98 | The payment amount depends on the variation of this agreement (according to 99 | section 3.1) into which you want to enter. Concrete prices are listed on 100 | OBJECTIVE DEVELOPMENT's web site, usually at 101 | http://www.obdev.at/vusb/license.html. You agree to pay the amount listed 102 | there to OBJECTIVE DEVELOPMENT or OBJECTIVE DEVELOPMENT's payment processor 103 | or reseller. 104 | 105 | 106 | 5 COPYRIGHT AND OWNERSHIP 107 | 108 | V-USB is protected by copyright laws and international copyright 109 | treaties, as well as other intellectual property laws and treaties. V-USB 110 | is licensed, not sold. 111 | 112 | 113 | 6 TERM AND TERMINATION 114 | 115 | 6.1 Term. This Agreement shall continue indefinitely. However, OBJECTIVE 116 | DEVELOPMENT may terminate this Agreement and revoke the granted license and 117 | USB-IDs if you fail to comply with any of its terms and conditions. 118 | 119 | 6.2 Survival of Terms. All provisions regarding secrecy, confidentiality 120 | and limitation of liability shall survive termination of this agreement. 121 | 122 | 123 | 7 DISCLAIMER OF WARRANTY AND LIABILITY 124 | 125 | LIMITED WARRANTY. V-USB IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 126 | KIND. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, OBJECTIVE 127 | DEVELOPMENT AND ITS SUPPLIERS HEREBY DISCLAIM ALL WARRANTIES, EITHER 128 | EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 129 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND 130 | NON-INFRINGEMENT, WITH REGARD TO V-USB, AND THE PROVISION OF OR FAILURE 131 | TO PROVIDE SUPPORT SERVICES. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL 132 | RIGHTS. YOU MAY HAVE OTHERS, WHICH VARY FROM STATE/JURISDICTION TO 133 | STATE/JURISDICTION. 134 | 135 | LIMITATION OF LIABILITY. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, 136 | IN NO EVENT SHALL OBJECTIVE DEVELOPMENT OR ITS SUPPLIERS BE LIABLE FOR ANY 137 | SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER 138 | (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, 139 | BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY OTHER PECUNIARY 140 | LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE V-USB OR THE 141 | PROVISION OF OR FAILURE TO PROVIDE SUPPORT SERVICES, EVEN IF OBJECTIVE 142 | DEVELOPMENT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN ANY 143 | CASE, OBJECTIVE DEVELOPMENT'S ENTIRE LIABILITY UNDER ANY PROVISION OF THIS 144 | AGREEMENT SHALL BE LIMITED TO THE AMOUNT ACTUALLY PAID BY YOU FOR V-USB. 145 | 146 | 147 | 8 MISCELLANEOUS TERMS 148 | 149 | 8.1 Marketing. OBJECTIVE DEVELOPMENT has the right to mention for marketing 150 | purposes that you entered into this agreement. 151 | 152 | 8.2 Entire Agreement. This document represents the entire agreement between 153 | OBJECTIVE DEVELOPMENT and you. It may only be modified in writing signed by 154 | an authorized representative of both, OBJECTIVE DEVELOPMENT and you. 155 | 156 | 8.3 Severability. In case a provision of these terms and conditions should 157 | be or become partly or entirely invalid, ineffective, or not executable, 158 | the validity of all other provisions shall not be affected. 159 | 160 | 8.4 Applicable Law. This agreement is governed by the laws of the Republic 161 | of Austria. 162 | 163 | 8.5 Responsible Courts. The responsible courts in Vienna/Austria will have 164 | exclusive jurisdiction regarding all disputes in connection with this 165 | agreement. 166 | 167 | -------------------------------------------------------------------------------- /firmware/asmcommon.inc: -------------------------------------------------------------------------------- 1 | /* Name: asmcommon.inc 2 | * Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2007-11-05 5 | * Tabsize: 4 6 | * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) 8 | */ 9 | 10 | /* Do not link this file! Link usbdrvasm.S instead, which includes the 11 | * appropriate implementation! 12 | */ 13 | 14 | /* 15 | General Description: 16 | This file contains assembler code which is shared among the USB driver 17 | implementations for different CPU cocks. Since the code must be inserted 18 | in the middle of the module, it's split out into this file and #included. 19 | 20 | Jump destinations called from outside: 21 | sofError: Called when no start sequence was found. 22 | se0: Called when a package has been successfully received. 23 | overflow: Called when receive buffer overflows. 24 | doReturn: Called after sending data. 25 | 26 | Outside jump destinations used by this module: 27 | waitForJ: Called to receive an already arriving packet. 28 | sendAckAndReti: 29 | sendNakAndReti: 30 | sendCntAndReti: 31 | usbSendAndReti: 32 | 33 | The following macros must be defined before this file is included: 34 | .macro POP_STANDARD 35 | .endm 36 | .macro POP_RETI 37 | .endm 38 | */ 39 | 40 | #define token x1 41 | 42 | overflow: 43 | ldi x2, 1< 26 | #include 27 | #include 28 | 29 | #include "i2cdrv.h" 30 | 31 | #define TWI_SCL PORTC0 32 | #define TWI_SDA PORTC1 33 | 34 | void i2cInit(unsigned char comSpeed) 35 | { 36 | // Setup I/O pin for I2C with pull-ups. 37 | DDRC |= ((1 << TWI_SDA) | (1 << TWI_SCL)); 38 | PORTC |= ((1 << TWI_SDA) | (1 << TWI_SCL)); 39 | DDRC &= ~((1 << TWI_SDA) | (1 << TWI_SCL)); 40 | 41 | // Limit speed configurations between 100kHz to 400kHz. 42 | if(comSpeed > TWI_COM_SPEED_400) 43 | { 44 | // Specified speed setting is not supported and switch to default speed. 45 | comSpeed = TWI_COM_SPEED_100; 46 | } 47 | 48 | // Set prescaler to 1. 49 | TWSR &= ~((1 << TWPS1) | (1 << TWPS0)); 50 | 51 | // Setup communication speed. 52 | switch(comSpeed) 53 | { 54 | case TWI_COM_SPEED_100: 55 | // I2C clock speed is set to 100kHz. 56 | TWBR = 72; 57 | break; 58 | case TWI_COM_SPEED_250: 59 | // I2C clock speed is set to 250kHz. 60 | TWBR = 24; 61 | break; 62 | case TWI_COM_SPEED_400: 63 | // I2C clock speed is set to 400kHz. 64 | TWBR = 12; 65 | break; 66 | } 67 | } 68 | 69 | unsigned char i2cStart(void (*usbProc)(void)) 70 | { 71 | unsigned short timeout = 0; 72 | 73 | // Send START condition to the slave device. 74 | TWCR = ((1 << TWINT) | (1 << TWEN) | (1 << TWSTA)); 75 | 76 | while (!(TWCR & (1 << TWINT))) 77 | { 78 | if((++timeout) >= I2C_TIMEOUT) 79 | { 80 | // Delay timeout has occured. 81 | return RET_TIMEOUT_FAIL; 82 | } 83 | 84 | _delay_us(I2C_DELAY_DELTA); 85 | (*usbProc)(); 86 | } 87 | 88 | // Send I2C status to the host system. 89 | return TW_STATUS; 90 | } 91 | 92 | unsigned char i2cWriteAddr(void (*usbProc)(void), unsigned char addr) 93 | { 94 | unsigned short timeout = 0; 95 | 96 | // Set device address with read/write flag. 97 | TWDR = addr; 98 | TWCR = ((1 << TWINT) | (1 << TWEN)); 99 | 100 | while (!(TWCR & (1 << TWINT))) 101 | { 102 | if((++timeout) >= I2C_TIMEOUT) 103 | { 104 | // Delay timeout has occured. 105 | return RET_TIMEOUT_FAIL; 106 | } 107 | 108 | _delay_us(I2C_DELAY_DELTA); 109 | (*usbProc)(); 110 | } 111 | 112 | // Send I2C status to the host system. 113 | return TW_STATUS; 114 | } 115 | 116 | unsigned char i2cWrite(void (*usbProc)(void), unsigned char data) 117 | { 118 | unsigned short timeout = 0; 119 | 120 | // Write specified data into slave device. 121 | TWDR = data; 122 | TWCR = ((1 << TWINT) | (1 << TWEN)); 123 | 124 | while (!(TWCR & (1 << TWINT))) 125 | { 126 | if((++timeout) >= I2C_TIMEOUT) 127 | { 128 | // Delay timeout has occured. 129 | return RET_TIMEOUT_FAIL; 130 | } 131 | 132 | _delay_us(I2C_DELAY_DELTA); 133 | (*usbProc)(); 134 | } 135 | 136 | // Send I2C status to the host system. 137 | return TW_STATUS; 138 | } 139 | 140 | unsigned char i2cRead(void (*usbProc)(void), unsigned char ack, unsigned char *data) 141 | { 142 | unsigned short timeout = 0; 143 | *data = 0; 144 | 145 | if(ack) 146 | { 147 | // Send ACK after the successful read. 148 | TWCR = ((1 << TWINT) | (1 << TWEN) | (1 << TWEA)); 149 | 150 | while (!(TWCR & (1 << TWINT))) 151 | { 152 | if((++timeout) >= I2C_TIMEOUT) 153 | { 154 | // Delay timeout has occured. 155 | return RET_TIMEOUT_FAIL; 156 | } 157 | 158 | _delay_us(I2C_DELAY_DELTA); 159 | (*usbProc)(); 160 | } 161 | 162 | *data = TWDR; 163 | 164 | // Send I2C status to the host system. 165 | return TW_STATUS; 166 | } 167 | else 168 | { 169 | // ACK is not sent after the successful read. 170 | TWCR = ((1 << TWINT) | (1 << TWEN)); 171 | while (!(TWCR & (1 << TWINT))) 172 | { 173 | if((++timeout) >= I2C_TIMEOUT) 174 | { 175 | // Delay timeout has occured. 176 | return RET_TIMEOUT_FAIL; 177 | } 178 | 179 | _delay_us(I2C_DELAY_DELTA); 180 | (*usbProc)(); 181 | } 182 | 183 | *data = TWDR; 184 | 185 | // Send I2C status to the host system. 186 | return TW_STATUS; 187 | } 188 | } 189 | 190 | void i2cStop() 191 | { 192 | // Send STOP condition to the device / bus. 193 | TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); 194 | } -------------------------------------------------------------------------------- /firmware/i2cdrv.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------------- 2 | // I2C Test Terminal Firmware - I2C Driver. 3 | // 4 | // Copyright (c) 2021 Dilshan R Jayakody [jayakody2000lk@gmail.com]. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | //---------------------------------------------------------------------------------- 24 | 25 | #ifndef I2C_DRIVER_HEADER 26 | #define I2C_DRIVER_HEADER 27 | 28 | #define RET_SUCCESS 0x00 29 | #define RET_PENDING 0x01 30 | #define RET_UNKNOWN 0x02 31 | #define RET_TIMEOUT_FAIL 0xFF 32 | 33 | #define I2C_TIMEOUT 0x7FF 34 | #define I2C_DELAY_DELTA 500 35 | 36 | // I2C speed configurations. 37 | #define TWI_COM_SPEED_100 0 // 100kHz 38 | #define TWI_COM_SPEED_250 1 // 250kHz 39 | #define TWI_COM_SPEED_400 2 // 400kHz 40 | 41 | void i2cInit(unsigned char comSpeed); 42 | unsigned char i2cStart(void (*usbProc)(void)); 43 | void i2cStop(); 44 | 45 | unsigned char i2cWriteAddr(void (*usbProc)(void), unsigned char addr); 46 | unsigned char i2cWrite(void (*usbProc)(void), unsigned char data); 47 | unsigned char i2cRead(void (*usbProc)(void), unsigned char ack, unsigned char *data); 48 | 49 | #endif /* I2C_DRIVER_HEADER */ -------------------------------------------------------------------------------- /firmware/i2ctester.c: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------------- 2 | // I2C Test Terminal Firmware - Core Functions and Main Entry Point. 3 | // 4 | // Copyright (c) 2021 Dilshan R Jayakody [jayakody2000lk@gmail.com]. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | //---------------------------------------------------------------------------------- 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "usbdrv.h" 31 | 32 | #include "i2ctester.h" 33 | #include "i2cdrv.h" 34 | 35 | PROGMEM const char usbHidReportDescriptor[22] = { /* USB report descriptor */ 36 | 0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop) 37 | 0x09, 0x01, // USAGE (Vendor Usage 1) 38 | 0xa1, 0x01, // COLLECTION (Application) 39 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 40 | 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 41 | 0x75, 0x08, // REPORT_SIZE (8) 42 | 0x95, 0x80, // REPORT_COUNT (128) 43 | 0x09, 0x00, // USAGE (Undefined) 44 | 0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf) 45 | 0xc0 // END_COLLECTION 46 | }; 47 | 48 | int main() 49 | { 50 | unsigned char connectDelay = 0; 51 | unsigned char outputVoltage = I2C_OUTPUT_3V3; 52 | 53 | // Initialize system registers and global variables. 54 | wdt_disable(); 55 | initSystem(); 56 | clearRequestBuffer(); 57 | 58 | // Check device is connected to the USB host. 59 | if((PINA & 0x01) == 0x00) 60 | { 61 | // Device is not connected to the USB host, waiting for connection. 62 | do 63 | { 64 | // Blink Device Status LED and check USB sense pin. 65 | if(PORTB & 0x04) 66 | { 67 | PORTB &= 0xFB; 68 | } 69 | else 70 | { 71 | PORTB |= 0x04; 72 | } 73 | 74 | _delay_ms(250); 75 | } 76 | while ((PINA & 0x01) == 0x00); 77 | } 78 | 79 | // USB device is connected to the host. 80 | PORTB |= 0x04; 81 | 82 | // Initialize V-USB driver. 83 | usbInit(); 84 | usbDeviceDisconnect(); 85 | 86 | while(--connectDelay) 87 | { 88 | _delay_ms(1); 89 | } 90 | 91 | usbDeviceConnect(); 92 | sei(); 93 | 94 | // Switch on lowest possible output voltage. 95 | setOutputVoltage(I2C_OUTPUT_3V3, &outputVoltage); 96 | 97 | // Main service loop. 98 | while(1) 99 | { 100 | // Check USB connection status. 101 | if((PINA & 0x01) == 0x00) 102 | { 103 | // Connection with USB host is not available, reset the device. 104 | PORTB &= 0xFB; 105 | 106 | // Activate WDT to perform device reset. 107 | cli(); 108 | wdt_enable(WDTO_15MS); 109 | while(1); 110 | } 111 | 112 | // Process pending USB messages and clear request buffer. 113 | if((reqBuffer[0] == SYS_SIGNATURE) && (reqBuffer[1] != USB_CMD_NONE)) 114 | { 115 | switch(reqBuffer[1]) 116 | { 117 | case USB_CMD_I2C_INIT: 118 | // Initialize I2C session. 119 | i2cInit(reqBuffer[2]); // DATA0 - I2C communication speed (ref: i2cdrv.h) 120 | lastCommandStatus = RET_SUCCESS; 121 | break; 122 | case USB_CMD_I2C_START: 123 | // Send I2C start command. 124 | lastCommandStatus = i2cStart(usbPoll); 125 | break; 126 | case USB_CMD_I2C_STOP: 127 | // Send I2C stop command. 128 | i2cStop(); 129 | lastCommandStatus = RET_SUCCESS; 130 | break; 131 | case USB_CMD_I2C_WRITE_ADDR: 132 | // Send I2C write address command. 133 | lastCommandStatus = i2cWriteAddr(usbPoll, reqBuffer[2]); // DATA0 - slave device address and read/write flag. 134 | break; 135 | case USB_CMD_I2C_WRITE: 136 | // Send I2C write command. 137 | lastCommandStatus = i2cWrite(usbPoll, reqBuffer[2]); // DATA0 - data to write into slave device. 138 | break; 139 | case USB_CMD_I2C_READ: 140 | // Send I2C read command. 141 | lastCommandStatus = i2cRead(usbPoll, reqBuffer[2], &lastCommandData); // DATA0 - ACK status for read command. 142 | break; 143 | case USB_CMD_SET_VOLTAGE: 144 | // Set I2C output voltage. 145 | lastCommandStatus = setOutputVoltage(reqBuffer[2], &outputVoltage); // DATA0 - Voltage level, 0x01 - 5V; 0x02 - 3.3V; 146 | break; 147 | case USB_CMD_GET_VOLTAGE: 148 | // Get current I2C output voltage. 149 | lastCommandData = outputVoltage; 150 | lastCommandStatus = RET_SUCCESS; 151 | break; 152 | case USB_CMD_RESET: 153 | // Reset I2C slave device and I2C terminal registers. 154 | lastCommandStatus = resetI2CSlave(outputVoltage); 155 | break; 156 | default: 157 | // Unknown command ID. 158 | lastCommandStatus = RET_UNKNOWN; 159 | } 160 | 161 | // Clear request buffer. 162 | clearRequestBuffer(); 163 | } 164 | 165 | // Process USB messages received from the host. 166 | usbPoll(); 167 | } 168 | 169 | return 0; 170 | } 171 | 172 | void initSystem() 173 | { 174 | // PORTB.0 [OUT] - 5V Control Terminal. 175 | // PORTB.1 [OUT] - 3.3V Control Terminal. 176 | // PORTB.2 [OUT] - Device Status LED. 177 | DDRB = 0x07; 178 | PORTB = I2C_OUTPUT_3V3; 179 | 180 | // Shutdown ADC and set PORTA.0 as USB sense pin. 181 | ADMUX = 0x00; 182 | ADCSRA = 0x00; 183 | ACSR = 0x80; 184 | 185 | DDRA = 0x00; 186 | PORTA = 0x00; 187 | 188 | // Initialize global variables. 189 | lastCommandStatus = RET_SUCCESS; 190 | lastCommandData = 0x00; 191 | lastCommand = USB_CMD_NONE; 192 | } 193 | 194 | void clearRequestBuffer() 195 | { 196 | reqBuffer[0] = 0x00; 197 | reqBuffer[1] = USB_CMD_NONE; 198 | reqBuffer[2] = 0x00; 199 | reqBuffer[3] = 0x00; 200 | } 201 | 202 | unsigned char usbFunctionRead(unsigned char *data, unsigned char len) 203 | { 204 | // Response data format: 205 | // SIGNATURE | COMMAND | STATUS | DATA | END SIGNATURE 206 | data[0] = SYS_SIGNATURE; 207 | data[1] = lastCommand; 208 | data[2] = lastCommandStatus; 209 | data[3] = lastCommandData; 210 | data[4] = SYS_END_SIGNATURE; 211 | 212 | return 4; 213 | } 214 | 215 | unsigned char usbFunctionWrite(unsigned char *data, unsigned char len) 216 | { 217 | // Received command format: 218 | // SIGNATURE | COMMAND | DATA BYTE | END SIGNATURE 219 | if((len > 4) && (data[0] == SYS_SIGNATURE)) 220 | { 221 | // Reset last command variables. 222 | lastCommandStatus = RET_PENDING; 223 | lastCommandData = 0x00; 224 | lastCommand = data[1]; 225 | 226 | // Copy received data into request buffer. 227 | reqBuffer[0] = data[0]; 228 | reqBuffer[1] = data[1]; 229 | reqBuffer[2] = data[2]; 230 | reqBuffer[3] = data[3]; 231 | } 232 | 233 | // End of the data chunk. 234 | return 1; 235 | } 236 | 237 | usbMsgLen_t usbFunctionSetup(unsigned char data[8]) 238 | { 239 | usbRequest_t *request = (void*)data; 240 | 241 | if((request->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) 242 | { 243 | // HID class request. 244 | if(request->bRequest == USBRQ_HID_GET_REPORT) 245 | { 246 | // use usbFunctionRead to obtain data. 247 | return USB_NO_MSG; 248 | } 249 | else if(request->bRequest == USBRQ_HID_SET_REPORT) 250 | { 251 | // use usbFunctionWrite to receive data from host. 252 | return USB_NO_MSG; 253 | } 254 | } 255 | 256 | return 0; 257 | } 258 | 259 | unsigned char setOutputVoltage(unsigned char voltage, unsigned char *newVoltage) 260 | { 261 | unsigned char countdown = 0xFF; 262 | 263 | // Shutdown both 3.3V and 5V output lines. 264 | PORTB &= 0xFC; 265 | 266 | // Wait to stable the output terminals. 267 | while(--countdown) 268 | { 269 | usbPoll(); 270 | _delay_us(I2C_DELAY_DELTA); 271 | } 272 | 273 | // Set new voltage level. 274 | if((voltage == I2C_OUTPUT_3V3) || (voltage == I2C_OUTPUT_5V)) 275 | { 276 | PORTB |= voltage; 277 | *newVoltage = voltage; 278 | return RET_SUCCESS; 279 | } 280 | 281 | // Voltage settings are invalid. 282 | return RET_UNKNOWN; 283 | } 284 | 285 | unsigned char resetI2CSlave(unsigned char voltage) 286 | { 287 | unsigned char countdown = 0x96; 288 | 289 | // Shutdown both 3.3V and 5V output lines. 290 | PORTB &= 0xFC; 291 | 292 | // Reset all I2C registers to default values. 293 | TWBR = 0x00; 294 | TWCR = 0x00; 295 | TWSR = 0xF8; 296 | TWDR = 0xFF; 297 | TWAR = 0xFE; 298 | 299 | // Wait to stable the output terminals. 300 | while(--countdown) 301 | { 302 | usbPoll(); 303 | _delay_us(I2C_DELAY_DELTA); 304 | } 305 | 306 | // Restore voltage to the slave device. 307 | PORTB |= voltage; 308 | return RET_SUCCESS; 309 | } -------------------------------------------------------------------------------- /firmware/i2ctester.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------------- 2 | // I2C Test Terminal Firmware - Core Functions and Main Entry Point. 3 | // 4 | // Copyright (c) 2021 Dilshan R Jayakody [jayakody2000lk@gmail.com]. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | //---------------------------------------------------------------------------------- 24 | 25 | #ifndef I2C_TESTER_MAIN_HEADER 26 | #define I2C_TESTER_MAIN_HEADER 27 | 28 | #define SYS_SIGNATURE 0x5D 29 | #define SYS_END_SIGNATURE 0x5A 30 | 31 | #define USB_CMD_NONE 0x00 32 | #define USB_CMD_I2C_INIT 0x01 33 | #define USB_CMD_I2C_START 0x02 34 | #define USB_CMD_I2C_STOP 0x03 35 | #define USB_CMD_I2C_WRITE_ADDR 0x04 36 | #define USB_CMD_I2C_WRITE 0x05 37 | #define USB_CMD_I2C_READ 0x06 38 | #define USB_CMD_SET_VOLTAGE 0x07 39 | #define USB_CMD_GET_VOLTAGE 0x08 40 | #define USB_CMD_RESET 0x09 41 | 42 | #define I2C_OUTPUT_5V 0x01 43 | #define I2C_OUTPUT_3V3 0x02 44 | 45 | static unsigned char reqBuffer[4]; 46 | 47 | static unsigned char lastCommandStatus; 48 | static unsigned char lastCommandData; 49 | static unsigned char lastCommand; 50 | 51 | void initSystem(); 52 | void clearRequestBuffer(); 53 | unsigned char setOutputVoltage(unsigned char voltage, unsigned char *newVoltage); 54 | unsigned char resetI2CSlave(unsigned char voltage); 55 | 56 | #endif /* I2C_TESTER_MAIN_HEADER */ -------------------------------------------------------------------------------- /firmware/oddebug.c: -------------------------------------------------------------------------------- 1 | /* Name: oddebug.c 2 | * Project: AVR library 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2005-01-16 5 | * Tabsize: 4 6 | * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) 8 | */ 9 | 10 | #include "oddebug.h" 11 | 12 | #if DEBUG_LEVEL > 0 13 | 14 | #warning "Never compile production devices with debugging enabled" 15 | 16 | static void uartPutc(char c) 17 | { 18 | while(!(ODDBG_USR & (1 << ODDBG_UDRE))); /* wait for data register empty */ 19 | ODDBG_UDR = c; 20 | } 21 | 22 | static uchar hexAscii(uchar h) 23 | { 24 | h &= 0xf; 25 | if(h >= 10) 26 | h += 'a' - (uchar)10 - '0'; 27 | h += '0'; 28 | return h; 29 | } 30 | 31 | static void printHex(uchar c) 32 | { 33 | uartPutc(hexAscii(c >> 4)); 34 | uartPutc(hexAscii(c)); 35 | } 36 | 37 | void odDebug(uchar prefix, uchar *data, uchar len) 38 | { 39 | printHex(prefix); 40 | uartPutc(':'); 41 | while(len--){ 42 | uartPutc(' '); 43 | printHex(*data++); 44 | } 45 | uartPutc('\r'); 46 | uartPutc('\n'); 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /firmware/oddebug.h: -------------------------------------------------------------------------------- 1 | /* Name: oddebug.h 2 | * Project: AVR library 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2005-01-16 5 | * Tabsize: 4 6 | * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) 8 | */ 9 | 10 | #ifndef __oddebug_h_included__ 11 | #define __oddebug_h_included__ 12 | 13 | /* 14 | General Description: 15 | This module implements a function for debug logs on the serial line of the 16 | AVR microcontroller. Debugging can be configured with the define 17 | 'DEBUG_LEVEL'. If this macro is not defined or defined to 0, all debugging 18 | calls are no-ops. If it is 1, DBG1 logs will appear, but not DBG2. If it is 19 | 2, DBG1 and DBG2 logs will be printed. 20 | 21 | A debug log consists of a label ('prefix') to indicate which debug log created 22 | the output and a memory block to dump in hex ('data' and 'len'). 23 | */ 24 | 25 | 26 | #ifndef F_CPU 27 | # define F_CPU 12000000 /* 12 MHz */ 28 | #endif 29 | 30 | /* make sure we have the UART defines: */ 31 | #include "usbportability.h" 32 | 33 | #ifndef uchar 34 | # define uchar unsigned char 35 | #endif 36 | 37 | #if DEBUG_LEVEL > 0 && !(defined TXEN || defined TXEN0) /* no UART in device */ 38 | # warning "Debugging disabled because device has no UART" 39 | # undef DEBUG_LEVEL 40 | #endif 41 | 42 | #ifndef DEBUG_LEVEL 43 | # define DEBUG_LEVEL 0 44 | #endif 45 | 46 | /* ------------------------------------------------------------------------- */ 47 | 48 | #if DEBUG_LEVEL > 0 49 | # define DBG1(prefix, data, len) odDebug(prefix, data, len) 50 | #else 51 | # define DBG1(prefix, data, len) 52 | #endif 53 | 54 | #if DEBUG_LEVEL > 1 55 | # define DBG2(prefix, data, len) odDebug(prefix, data, len) 56 | #else 57 | # define DBG2(prefix, data, len) 58 | #endif 59 | 60 | /* ------------------------------------------------------------------------- */ 61 | 62 | #if DEBUG_LEVEL > 0 63 | extern void odDebug(uchar prefix, uchar *data, uchar len); 64 | 65 | /* Try to find our control registers; ATMEL likes to rename these */ 66 | 67 | #if defined UBRR 68 | # define ODDBG_UBRR UBRR 69 | #elif defined UBRRL 70 | # define ODDBG_UBRR UBRRL 71 | #elif defined UBRR0 72 | # define ODDBG_UBRR UBRR0 73 | #elif defined UBRR0L 74 | # define ODDBG_UBRR UBRR0L 75 | #endif 76 | 77 | #if defined UCR 78 | # define ODDBG_UCR UCR 79 | #elif defined UCSRB 80 | # define ODDBG_UCR UCSRB 81 | #elif defined UCSR0B 82 | # define ODDBG_UCR UCSR0B 83 | #endif 84 | 85 | #if defined TXEN 86 | # define ODDBG_TXEN TXEN 87 | #else 88 | # define ODDBG_TXEN TXEN0 89 | #endif 90 | 91 | #if defined USR 92 | # define ODDBG_USR USR 93 | #elif defined UCSRA 94 | # define ODDBG_USR UCSRA 95 | #elif defined UCSR0A 96 | # define ODDBG_USR UCSR0A 97 | #endif 98 | 99 | #if defined UDRE 100 | # define ODDBG_UDRE UDRE 101 | #else 102 | # define ODDBG_UDRE UDRE0 103 | #endif 104 | 105 | #if defined UDR 106 | # define ODDBG_UDR UDR 107 | #elif defined UDR0 108 | # define ODDBG_UDR UDR0 109 | #endif 110 | 111 | static inline void odDebugInit(void) 112 | { 113 | ODDBG_UCR |= (1< max 25 cycles interrupt disable 38 | ;max stack usage: [ret(2), YL, SREG, YH, shift, x1, x2, x3, cnt, x4] = 11 bytes 39 | ;Numbers in brackets are maximum cycles since SOF. 40 | USB_INTR_VECTOR: 41 | ;order of registers pushed: YL, SREG [sofError], YH, shift, x1, x2, x3, cnt 42 | push YL ;2 [35] push only what is necessary to sync with edge ASAP 43 | in YL, SREG ;1 [37] 44 | push YL ;2 [39] 45 | ;---------------------------------------------------------------------------- 46 | ; Synchronize with sync pattern: 47 | ;---------------------------------------------------------------------------- 48 | ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] 49 | ;sync up with J to K edge during sync pattern -- use fastest possible loops 50 | ;The first part waits at most 1 bit long since we must be in sync pattern. 51 | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to 52 | ;waitForJ, ensure that this prerequisite is met. 53 | waitForJ: 54 | inc YL 55 | sbis USBIN, USBMINUS 56 | brne waitForJ ; just make sure we have ANY timeout 57 | waitForK: 58 | ;The following code results in a sampling window of 1/4 bit which meets the spec. 59 | sbis USBIN, USBMINUS 60 | rjmp foundK 61 | sbis USBIN, USBMINUS 62 | rjmp foundK 63 | sbis USBIN, USBMINUS 64 | rjmp foundK 65 | sbis USBIN, USBMINUS 66 | rjmp foundK 67 | sbis USBIN, USBMINUS 68 | rjmp foundK 69 | #if USB_COUNT_SOF 70 | lds YL, usbSofCount 71 | inc YL 72 | sts usbSofCount, YL 73 | #endif /* USB_COUNT_SOF */ 74 | #ifdef USB_SOF_HOOK 75 | USB_SOF_HOOK 76 | #endif 77 | rjmp sofError 78 | foundK: 79 | ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling] 80 | ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets 81 | ;are cycles from center of first sync (double K) bit after the instruction 82 | push YH ;2 [2] 83 | lds YL, usbInputBufOffset;2 [4] 84 | clr YH ;1 [5] 85 | subi YL, lo8(-(usbRxBuf));1 [6] 86 | sbci YH, hi8(-(usbRxBuf));1 [7] 87 | 88 | sbis USBIN, USBMINUS ;1 [8] we want two bits K [sample 1 cycle too early] 89 | rjmp haveTwoBitsK ;2 [10] 90 | pop YH ;2 [11] undo the push from before 91 | rjmp waitForK ;2 [13] this was not the end of sync, retry 92 | haveTwoBitsK: 93 | ;---------------------------------------------------------------------------- 94 | ; push more registers and initialize values while we sample the first bits: 95 | ;---------------------------------------------------------------------------- 96 | push shift ;2 [16] 97 | push x1 ;2 [12] 98 | push x2 ;2 [14] 99 | 100 | in x1, USBIN ;1 [17] <-- sample bit 0 101 | ldi shift, 0xff ;1 [18] 102 | bst x1, USBMINUS ;1 [19] 103 | bld shift, 0 ;1 [20] 104 | push x3 ;2 [22] 105 | push cnt ;2 [24] 106 | 107 | in x2, USBIN ;1 [25] <-- sample bit 1 108 | ser x3 ;1 [26] [inserted init instruction] 109 | eor x1, x2 ;1 [27] 110 | bst x1, USBMINUS ;1 [28] 111 | bld shift, 1 ;1 [29] 112 | ldi cnt, USB_BUFSIZE;1 [30] [inserted init instruction] 113 | rjmp rxbit2 ;2 [32] 114 | 115 | ;---------------------------------------------------------------------------- 116 | ; Receiver loop (numbers in brackets are cycles within byte after instr) 117 | ;---------------------------------------------------------------------------- 118 | 119 | unstuff0: ;1 (branch taken) 120 | andi x3, ~0x01 ;1 [15] 121 | mov x1, x2 ;1 [16] x2 contains last sampled (stuffed) bit 122 | in x2, USBIN ;1 [17] <-- sample bit 1 again 123 | ori shift, 0x01 ;1 [18] 124 | rjmp didUnstuff0 ;2 [20] 125 | 126 | unstuff1: ;1 (branch taken) 127 | mov x2, x1 ;1 [21] x1 contains last sampled (stuffed) bit 128 | andi x3, ~0x02 ;1 [22] 129 | ori shift, 0x02 ;1 [23] 130 | nop ;1 [24] 131 | in x1, USBIN ;1 [25] <-- sample bit 2 again 132 | rjmp didUnstuff1 ;2 [27] 133 | 134 | unstuff2: ;1 (branch taken) 135 | andi x3, ~0x04 ;1 [29] 136 | ori shift, 0x04 ;1 [30] 137 | mov x1, x2 ;1 [31] x2 contains last sampled (stuffed) bit 138 | nop ;1 [32] 139 | in x2, USBIN ;1 [33] <-- sample bit 3 140 | rjmp didUnstuff2 ;2 [35] 141 | 142 | unstuff3: ;1 (branch taken) 143 | in x2, USBIN ;1 [34] <-- sample stuffed bit 3 [one cycle too late] 144 | andi x3, ~0x08 ;1 [35] 145 | ori shift, 0x08 ;1 [36] 146 | rjmp didUnstuff3 ;2 [38] 147 | 148 | unstuff4: ;1 (branch taken) 149 | andi x3, ~0x10 ;1 [40] 150 | in x1, USBIN ;1 [41] <-- sample stuffed bit 4 151 | ori shift, 0x10 ;1 [42] 152 | rjmp didUnstuff4 ;2 [44] 153 | 154 | unstuff5: ;1 (branch taken) 155 | andi x3, ~0x20 ;1 [48] 156 | in x2, USBIN ;1 [49] <-- sample stuffed bit 5 157 | ori shift, 0x20 ;1 [50] 158 | rjmp didUnstuff5 ;2 [52] 159 | 160 | unstuff6: ;1 (branch taken) 161 | andi x3, ~0x40 ;1 [56] 162 | in x1, USBIN ;1 [57] <-- sample stuffed bit 6 163 | ori shift, 0x40 ;1 [58] 164 | rjmp didUnstuff6 ;2 [60] 165 | 166 | ; extra jobs done during bit interval: 167 | ; bit 0: store, clear [SE0 is unreliable here due to bit dribbling in hubs] 168 | ; bit 1: se0 check 169 | ; bit 2: overflow check 170 | ; bit 3: recovery from delay [bit 0 tasks took too long] 171 | ; bit 4: none 172 | ; bit 5: none 173 | ; bit 6: none 174 | ; bit 7: jump, eor 175 | rxLoop: 176 | eor x3, shift ;1 [0] reconstruct: x3 is 0 at bit locations we changed, 1 at others 177 | in x1, USBIN ;1 [1] <-- sample bit 0 178 | st y+, x3 ;2 [3] store data 179 | ser x3 ;1 [4] 180 | nop ;1 [5] 181 | eor x2, x1 ;1 [6] 182 | bst x2, USBMINUS;1 [7] 183 | bld shift, 0 ;1 [8] 184 | in x2, USBIN ;1 [9] <-- sample bit 1 (or possibly bit 0 stuffed) 185 | andi x2, USBMASK ;1 [10] 186 | breq se0 ;1 [11] SE0 check for bit 1 187 | andi shift, 0xf9 ;1 [12] 188 | didUnstuff0: 189 | breq unstuff0 ;1 [13] 190 | eor x1, x2 ;1 [14] 191 | bst x1, USBMINUS;1 [15] 192 | bld shift, 1 ;1 [16] 193 | rxbit2: 194 | in x1, USBIN ;1 [17] <-- sample bit 2 (or possibly bit 1 stuffed) 195 | andi shift, 0xf3 ;1 [18] 196 | breq unstuff1 ;1 [19] do remaining work for bit 1 197 | didUnstuff1: 198 | subi cnt, 1 ;1 [20] 199 | brcs overflow ;1 [21] loop control 200 | eor x2, x1 ;1 [22] 201 | bst x2, USBMINUS;1 [23] 202 | bld shift, 2 ;1 [24] 203 | in x2, USBIN ;1 [25] <-- sample bit 3 (or possibly bit 2 stuffed) 204 | andi shift, 0xe7 ;1 [26] 205 | breq unstuff2 ;1 [27] 206 | didUnstuff2: 207 | eor x1, x2 ;1 [28] 208 | bst x1, USBMINUS;1 [29] 209 | bld shift, 3 ;1 [30] 210 | didUnstuff3: 211 | andi shift, 0xcf ;1 [31] 212 | breq unstuff3 ;1 [32] 213 | in x1, USBIN ;1 [33] <-- sample bit 4 214 | eor x2, x1 ;1 [34] 215 | bst x2, USBMINUS;1 [35] 216 | bld shift, 4 ;1 [36] 217 | didUnstuff4: 218 | andi shift, 0x9f ;1 [37] 219 | breq unstuff4 ;1 [38] 220 | nop2 ;2 [40] 221 | in x2, USBIN ;1 [41] <-- sample bit 5 222 | eor x1, x2 ;1 [42] 223 | bst x1, USBMINUS;1 [43] 224 | bld shift, 5 ;1 [44] 225 | didUnstuff5: 226 | andi shift, 0x3f ;1 [45] 227 | breq unstuff5 ;1 [46] 228 | nop2 ;2 [48] 229 | in x1, USBIN ;1 [49] <-- sample bit 6 230 | eor x2, x1 ;1 [50] 231 | bst x2, USBMINUS;1 [51] 232 | bld shift, 6 ;1 [52] 233 | didUnstuff6: 234 | cpi shift, 0x02 ;1 [53] 235 | brlo unstuff6 ;1 [54] 236 | nop2 ;2 [56] 237 | in x2, USBIN ;1 [57] <-- sample bit 7 238 | eor x1, x2 ;1 [58] 239 | bst x1, USBMINUS;1 [59] 240 | bld shift, 7 ;1 [60] 241 | didUnstuff7: 242 | cpi shift, 0x04 ;1 [61] 243 | brsh rxLoop ;2 [63] loop control 244 | unstuff7: 245 | andi x3, ~0x80 ;1 [63] 246 | ori shift, 0x80 ;1 [64] 247 | in x2, USBIN ;1 [65] <-- sample stuffed bit 7 248 | nop ;1 [66] 249 | rjmp didUnstuff7 ;2 [68] 250 | 251 | macro POP_STANDARD ; 12 cycles 252 | pop cnt 253 | pop x3 254 | pop x2 255 | pop x1 256 | pop shift 257 | pop YH 258 | endm 259 | macro POP_RETI ; 5 cycles 260 | pop YL 261 | out SREG, YL 262 | pop YL 263 | endm 264 | 265 | #include "asmcommon.inc" 266 | 267 | ;---------------------------------------------------------------------------- 268 | ; Transmitting data 269 | ;---------------------------------------------------------------------------- 270 | 271 | txByteLoop: 272 | txBitloop: 273 | stuffN1Delay: ; [03] 274 | ror shift ;[-5] [11] [59] 275 | brcc doExorN1 ;[-4] [60] 276 | subi x4, 1 ;[-3] 277 | brne commonN1 ;[-2] 278 | lsl shift ;[-1] compensate ror after rjmp stuffDelay 279 | nop ;[00] stuffing consists of just waiting 8 cycles 280 | rjmp stuffN1Delay ;[01] after ror, C bit is reliably clear 281 | 282 | sendNakAndReti: ;0 [-19] 19 cycles until SOP 283 | ldi x3, USBPID_NAK ;1 [-18] 284 | rjmp usbSendX3 ;2 [-16] 285 | sendAckAndReti: ;0 [-19] 19 cycles until SOP 286 | ldi x3, USBPID_ACK ;1 [-18] 287 | rjmp usbSendX3 ;2 [-16] 288 | sendCntAndReti: ;0 [-17] 17 cycles until SOP 289 | mov x3, cnt ;1 [-16] 290 | usbSendX3: ;0 [-16] 291 | ldi YL, 20 ;1 [-15] 'x3' is R20 292 | ldi YH, 0 ;1 [-14] 293 | ldi cnt, 2 ;1 [-13] 294 | ; rjmp usbSendAndReti fallthrough 295 | 296 | ; USB spec says: 297 | ; idle = J 298 | ; J = (D+ = 0), (D- = 1) or USBOUT = 0x01 299 | ; K = (D+ = 1), (D- = 0) or USBOUT = 0x02 300 | ; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles) 301 | 302 | ;usbSend: 303 | ;pointer to data in 'Y' 304 | ;number of bytes in 'cnt' -- including sync byte 305 | ;uses: x1...x2, x4, shift, cnt, Y [x1 = mirror USBOUT, x2 = USBMASK, x4 = bitstuff cnt] 306 | ;Numbers in brackets are time since first bit of sync pattern is sent (start of instruction) 307 | usbSendAndReti: 308 | in x2, USBDDR ;[-12] 12 cycles until SOP 309 | ori x2, USBMASK ;[-11] 310 | sbi USBOUT, USBMINUS ;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) 311 | out USBDDR, x2 ;[-8] <--- acquire bus 312 | in x1, USBOUT ;[-7] port mirror for tx loop 313 | ldi shift, 0x40 ;[-6] sync byte is first byte sent (we enter loop after ror) 314 | ldi x2, USBMASK ;[-5] 315 | push x4 ;[-4] 316 | doExorN1: 317 | eor x1, x2 ;[-2] [06] [62] 318 | ldi x4, 6 ;[-1] [07] [63] 319 | commonN1: 320 | stuffN2Delay: 321 | out USBOUT, x1 ;[00] [08] [64] <--- set bit 322 | ror shift ;[01] 323 | brcc doExorN2 ;[02] 324 | subi x4, 1 ;[03] 325 | brne commonN2 ;[04] 326 | lsl shift ;[05] compensate ror after rjmp stuffDelay 327 | rjmp stuffN2Delay ;[06] after ror, C bit is reliably clear 328 | doExorN2: 329 | eor x1, x2 ;[04] [12] 330 | ldi x4, 6 ;[05] [13] 331 | commonN2: 332 | nop ;[06] [14] 333 | subi cnt, 171 ;[07] [15] trick: (3 * 171) & 0xff = 1 334 | out USBOUT, x1 ;[08] [16] <--- set bit 335 | brcs txBitloop ;[09] [25] [41] 336 | 337 | stuff6Delay: 338 | ror shift ;[42] [50] 339 | brcc doExor6 ;[43] 340 | subi x4, 1 ;[44] 341 | brne common6 ;[45] 342 | lsl shift ;[46] compensate ror after rjmp stuffDelay 343 | nop ;[47] stuffing consists of just waiting 8 cycles 344 | rjmp stuff6Delay ;[48] after ror, C bit is reliably clear 345 | doExor6: 346 | eor x1, x2 ;[45] [53] 347 | ldi x4, 6 ;[46] 348 | common6: 349 | stuff7Delay: 350 | ror shift ;[47] [55] 351 | out USBOUT, x1 ;[48] <--- set bit 352 | brcc doExor7 ;[49] 353 | subi x4, 1 ;[50] 354 | brne common7 ;[51] 355 | lsl shift ;[52] compensate ror after rjmp stuffDelay 356 | rjmp stuff7Delay ;[53] after ror, C bit is reliably clear 357 | doExor7: 358 | eor x1, x2 ;[51] [59] 359 | ldi x4, 6 ;[52] 360 | common7: 361 | ld shift, y+ ;[53] 362 | tst cnt ;[55] 363 | out USBOUT, x1 ;[56] <--- set bit 364 | brne txByteLoop ;[57] 365 | 366 | ;make SE0: 367 | cbr x1, USBMASK ;[58] prepare SE0 [spec says EOP may be 15 to 18 cycles] 368 | lds x2, usbNewDeviceAddr;[59] 369 | lsl x2 ;[61] we compare with left shifted address 370 | subi YL, 2 + 20 ;[62] Only assign address on data packets, not ACK/NAK in x3 371 | sbci YH, 0 ;[63] 372 | out USBOUT, x1 ;[00] <-- out SE0 -- from now 2 bits = 16 cycles until bus idle 373 | ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: 374 | ;set address only after data packet was sent, not after handshake 375 | breq skipAddrAssign ;[01] 376 | sts usbDeviceAddr, x2 ; if not skipped: SE0 is one cycle longer 377 | skipAddrAssign: 378 | ;end of usbDeviceAddress transfer 379 | ldi x2, 1< 10.6666666 cycles per bit, 85.333333333 cycles per byte 29 | ; Numbers in brackets are clocks counted from center of last sync bit 30 | ; when instruction starts 31 | 32 | USB_INTR_VECTOR: 33 | ;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt 34 | push YL ;[-25] push only what is necessary to sync with edge ASAP 35 | in YL, SREG ;[-23] 36 | push YL ;[-22] 37 | push YH ;[-20] 38 | ;---------------------------------------------------------------------------- 39 | ; Synchronize with sync pattern: 40 | ;---------------------------------------------------------------------------- 41 | ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] 42 | ;sync up with J to K edge during sync pattern -- use fastest possible loops 43 | ;The first part waits at most 1 bit long since we must be in sync pattern. 44 | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to 45 | ;waitForJ, ensure that this prerequisite is met. 46 | waitForJ: 47 | inc YL 48 | sbis USBIN, USBMINUS 49 | brne waitForJ ; just make sure we have ANY timeout 50 | waitForK: 51 | ;The following code results in a sampling window of < 1/4 bit which meets the spec. 52 | sbis USBIN, USBMINUS ;[-15] 53 | rjmp foundK ;[-14] 54 | sbis USBIN, USBMINUS 55 | rjmp foundK 56 | sbis USBIN, USBMINUS 57 | rjmp foundK 58 | sbis USBIN, USBMINUS 59 | rjmp foundK 60 | sbis USBIN, USBMINUS 61 | rjmp foundK 62 | sbis USBIN, USBMINUS 63 | rjmp foundK 64 | #if USB_COUNT_SOF 65 | lds YL, usbSofCount 66 | inc YL 67 | sts usbSofCount, YL 68 | #endif /* USB_COUNT_SOF */ 69 | #ifdef USB_SOF_HOOK 70 | USB_SOF_HOOK 71 | #endif 72 | rjmp sofError 73 | foundK: ;[-12] 74 | ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling] 75 | ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets 76 | ;are cycles from center of first sync (double K) bit after the instruction 77 | push bitcnt ;[-12] 78 | ; [---] ;[-11] 79 | lds YL, usbInputBufOffset;[-10] 80 | ; [---] ;[-9] 81 | clr YH ;[-8] 82 | subi YL, lo8(-(usbRxBuf));[-7] [rx loop init] 83 | sbci YH, hi8(-(usbRxBuf));[-6] [rx loop init] 84 | push shift ;[-5] 85 | ; [---] ;[-4] 86 | ldi bitcnt, 0x55 ;[-3] [rx loop init] 87 | sbis USBIN, USBMINUS ;[-2] we want two bits K (sample 2 cycles too early) 88 | rjmp haveTwoBitsK ;[-1] 89 | pop shift ;[0] undo the push from before 90 | pop bitcnt ;[2] undo the push from before 91 | rjmp waitForK ;[4] this was not the end of sync, retry 92 | ; The entire loop from waitForK until rjmp waitForK above must not exceed two 93 | ; bit times (= 21 cycles). 94 | 95 | ;---------------------------------------------------------------------------- 96 | ; push more registers and initialize values while we sample the first bits: 97 | ;---------------------------------------------------------------------------- 98 | haveTwoBitsK: 99 | push x1 ;[1] 100 | push x2 ;[3] 101 | push x3 ;[5] 102 | ldi shift, 0 ;[7] 103 | ldi x3, 1<<4 ;[8] [rx loop init] first sample is inverse bit, compensate that 104 | push x4 ;[9] == leap 105 | 106 | in x1, USBIN ;[11] <-- sample bit 0 107 | andi x1, USBMASK ;[12] 108 | bst x1, USBMINUS ;[13] 109 | bld shift, 7 ;[14] 110 | push cnt ;[15] 111 | ldi leap, 0 ;[17] [rx loop init] 112 | ldi cnt, USB_BUFSIZE;[18] [rx loop init] 113 | rjmp rxbit1 ;[19] arrives at [21] 114 | 115 | ;---------------------------------------------------------------------------- 116 | ; Receiver loop (numbers in brackets are cycles within byte after instr) 117 | ;---------------------------------------------------------------------------- 118 | 119 | ; duration of unstuffing code should be 10.66666667 cycles. We adjust "leap" 120 | ; accordingly to approximate this value in the long run. 121 | 122 | unstuff6: 123 | andi x2, USBMASK ;[03] 124 | ori x3, 1<<6 ;[04] will not be shifted any more 125 | andi shift, ~0x80;[05] 126 | mov x1, x2 ;[06] sampled bit 7 is actually re-sampled bit 6 127 | subi leap, -1 ;[07] total duration = 11 bits -> subtract 1/3 128 | rjmp didUnstuff6 ;[08] 129 | 130 | unstuff7: 131 | ori x3, 1<<7 ;[09] will not be shifted any more 132 | in x2, USBIN ;[00] [10] re-sample bit 7 133 | andi x2, USBMASK ;[01] 134 | andi shift, ~0x80;[02] 135 | subi leap, 2 ;[03] total duration = 10 bits -> add 1/3 136 | rjmp didUnstuff7 ;[04] 137 | 138 | unstuffEven: 139 | ori x3, 1<<6 ;[09] will be shifted right 6 times for bit 0 140 | in x1, USBIN ;[00] [10] 141 | andi shift, ~0x80;[01] 142 | andi x1, USBMASK ;[02] 143 | breq se0 ;[03] 144 | subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3 145 | nop2 ;[05] 146 | rjmp didUnstuffE ;[06] 147 | 148 | unstuffOdd: 149 | ori x3, 1<<5 ;[09] will be shifted right 4 times for bit 1 150 | in x2, USBIN ;[00] [10] 151 | andi shift, ~0x80;[01] 152 | andi x2, USBMASK ;[02] 153 | breq se0 ;[03] 154 | subi leap, -1 ;[04] total duration = 11 bits -> subtract 1/3 155 | nop2 ;[05] 156 | rjmp didUnstuffO ;[06] 157 | 158 | rxByteLoop: 159 | andi x1, USBMASK ;[03] 160 | eor x2, x1 ;[04] 161 | subi leap, 1 ;[05] 162 | brpl skipLeap ;[06] 163 | subi leap, -3 ;1 one leap cycle every 3rd byte -> 85 + 1/3 cycles per byte 164 | nop ;1 165 | skipLeap: 166 | subi x2, 1 ;[08] 167 | ror shift ;[09] 168 | didUnstuff6: 169 | cpi shift, 0xfc ;[10] 170 | in x2, USBIN ;[00] [11] <-- sample bit 7 171 | brcc unstuff6 ;[01] 172 | andi x2, USBMASK ;[02] 173 | eor x1, x2 ;[03] 174 | subi x1, 1 ;[04] 175 | ror shift ;[05] 176 | didUnstuff7: 177 | cpi shift, 0xfc ;[06] 178 | brcc unstuff7 ;[07] 179 | eor x3, shift ;[08] reconstruct: x3 is 1 at bit locations we changed, 0 at others 180 | st y+, x3 ;[09] store data 181 | rxBitLoop: 182 | in x1, USBIN ;[00] [11] <-- sample bit 0/2/4 183 | andi x1, USBMASK ;[01] 184 | eor x2, x1 ;[02] 185 | andi x3, 0x3f ;[03] topmost two bits reserved for 6 and 7 186 | subi x2, 1 ;[04] 187 | ror shift ;[05] 188 | cpi shift, 0xfc ;[06] 189 | brcc unstuffEven ;[07] 190 | didUnstuffE: 191 | lsr x3 ;[08] 192 | lsr x3 ;[09] 193 | rxbit1: 194 | in x2, USBIN ;[00] [10] <-- sample bit 1/3/5 195 | andi x2, USBMASK ;[01] 196 | breq se0 ;[02] 197 | eor x1, x2 ;[03] 198 | subi x1, 1 ;[04] 199 | ror shift ;[05] 200 | cpi shift, 0xfc ;[06] 201 | brcc unstuffOdd ;[07] 202 | didUnstuffO: 203 | subi bitcnt, 0xab;[08] == addi 0x55, 0x55 = 0x100/3 204 | brcs rxBitLoop ;[09] 205 | 206 | subi cnt, 1 ;[10] 207 | in x1, USBIN ;[00] [11] <-- sample bit 6 208 | brcc rxByteLoop ;[01] 209 | rjmp overflow 210 | 211 | macro POP_STANDARD ; 14 cycles 212 | pop cnt 213 | pop x4 214 | pop x3 215 | pop x2 216 | pop x1 217 | pop shift 218 | pop bitcnt 219 | endm 220 | macro POP_RETI ; 7 cycles 221 | pop YH 222 | pop YL 223 | out SREG, YL 224 | pop YL 225 | endm 226 | 227 | #include "asmcommon.inc" 228 | 229 | ; USB spec says: 230 | ; idle = J 231 | ; J = (D+ = 0), (D- = 1) 232 | ; K = (D+ = 1), (D- = 0) 233 | ; Spec allows 7.5 bit times from EOP to SOP for replies 234 | 235 | bitstuffN: 236 | eor x1, x4 ;[5] 237 | ldi x2, 0 ;[6] 238 | nop2 ;[7] 239 | nop ;[9] 240 | out USBOUT, x1 ;[10] <-- out 241 | rjmp didStuffN ;[0] 242 | 243 | bitstuff6: 244 | eor x1, x4 ;[5] 245 | ldi x2, 0 ;[6] Carry is zero due to brcc 246 | rol shift ;[7] compensate for ror shift at branch destination 247 | rjmp didStuff6 ;[8] 248 | 249 | bitstuff7: 250 | ldi x2, 0 ;[2] Carry is zero due to brcc 251 | rjmp didStuff7 ;[3] 252 | 253 | 254 | sendNakAndReti: 255 | ldi x3, USBPID_NAK ;[-18] 256 | rjmp sendX3AndReti ;[-17] 257 | sendAckAndReti: 258 | ldi cnt, USBPID_ACK ;[-17] 259 | sendCntAndReti: 260 | mov x3, cnt ;[-16] 261 | sendX3AndReti: 262 | ldi YL, 20 ;[-15] x3==r20 address is 20 263 | ldi YH, 0 ;[-14] 264 | ldi cnt, 2 ;[-13] 265 | ; rjmp usbSendAndReti fallthrough 266 | 267 | ;usbSend: 268 | ;pointer to data in 'Y' 269 | ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] 270 | ;uses: x1...x4, btcnt, shift, cnt, Y 271 | ;Numbers in brackets are time since first bit of sync pattern is sent 272 | ;We don't match the transfer rate exactly (don't insert leap cycles every third 273 | ;byte) because the spec demands only 1.5% precision anyway. 274 | usbSendAndReti: ; 12 cycles until SOP 275 | in x2, USBDDR ;[-12] 276 | ori x2, USBMASK ;[-11] 277 | sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) 278 | in x1, USBOUT ;[-8] port mirror for tx loop 279 | out USBDDR, x2 ;[-7] <- acquire bus 280 | ; need not init x2 (bitstuff history) because sync starts with 0 281 | ldi x4, USBMASK ;[-6] exor mask 282 | ldi shift, 0x80 ;[-5] sync byte is first byte sent 283 | txByteLoop: 284 | ldi bitcnt, 0x35 ;[-4] [6] binary 0011 0101 285 | txBitLoop: 286 | sbrs shift, 0 ;[-3] [7] 287 | eor x1, x4 ;[-2] [8] 288 | out USBOUT, x1 ;[-1] [9] <-- out N 289 | ror shift ;[0] [10] 290 | ror x2 ;[1] 291 | didStuffN: 292 | cpi x2, 0xfc ;[2] 293 | brcc bitstuffN ;[3] 294 | lsr bitcnt ;[4] 295 | brcc txBitLoop ;[5] 296 | brne txBitLoop ;[6] 297 | 298 | sbrs shift, 0 ;[7] 299 | eor x1, x4 ;[8] 300 | didStuff6: 301 | out USBOUT, x1 ;[-1] [9] <-- out 6 302 | ror shift ;[0] [10] 303 | ror x2 ;[1] 304 | cpi x2, 0xfc ;[2] 305 | brcc bitstuff6 ;[3] 306 | ror shift ;[4] 307 | didStuff7: 308 | ror x2 ;[5] 309 | sbrs x2, 7 ;[6] 310 | eor x1, x4 ;[7] 311 | nop ;[8] 312 | cpi x2, 0xfc ;[9] 313 | out USBOUT, x1 ;[-1][10] <-- out 7 314 | brcc bitstuff7 ;[0] [11] 315 | ld shift, y+ ;[1] 316 | dec cnt ;[3] 317 | brne txByteLoop ;[4] 318 | ;make SE0: 319 | cbr x1, USBMASK ;[5] prepare SE0 [spec says EOP may be 21 to 25 cycles] 320 | lds x2, usbNewDeviceAddr;[6] 321 | lsl x2 ;[8] we compare with left shifted address 322 | subi YL, 20 + 2 ;[9] Only assign address on data packets, not ACK/NAK in x3 323 | sbci YH, 0 ;[10] 324 | out USBOUT, x1 ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle 325 | ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: 326 | ;set address only after data packet was sent, not after handshake 327 | breq skipAddrAssign ;[0] 328 | sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer 329 | skipAddrAssign: 330 | ;end of usbDeviceAddress transfer 331 | ldi x2, 1< max 52 cycles interrupt disable 31 | ;max stack usage: [ret(2), r0, SREG, YL, YH, shift, x1, x2, x3, x4, cnt] = 12 bytes 32 | ;nominal frequency: 16.5 MHz -> 11 cycles per bit 33 | ; 16.3125 MHz < F_CPU < 16.6875 MHz (+/- 1.1%) 34 | ; Numbers in brackets are clocks counted from center of last sync bit 35 | ; when instruction starts 36 | 37 | 38 | USB_INTR_VECTOR: 39 | ;order of registers pushed: YL, SREG [sofError], r0, YH, shift, x1, x2, x3, x4, cnt 40 | push YL ;[-23] push only what is necessary to sync with edge ASAP 41 | in YL, SREG ;[-21] 42 | push YL ;[-20] 43 | ;---------------------------------------------------------------------------- 44 | ; Synchronize with sync pattern: 45 | ;---------------------------------------------------------------------------- 46 | ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] 47 | ;sync up with J to K edge during sync pattern -- use fastest possible loops 48 | ;The first part waits at most 1 bit long since we must be in sync pattern. 49 | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to 50 | ;waitForJ, ensure that this prerequisite is met. 51 | waitForJ: 52 | inc YL 53 | sbis USBIN, USBMINUS 54 | brne waitForJ ; just make sure we have ANY timeout 55 | waitForK: 56 | ;The following code results in a sampling window of < 1/4 bit which meets the spec. 57 | sbis USBIN, USBMINUS ;[-15] 58 | rjmp foundK ;[-14] 59 | sbis USBIN, USBMINUS 60 | rjmp foundK 61 | sbis USBIN, USBMINUS 62 | rjmp foundK 63 | sbis USBIN, USBMINUS 64 | rjmp foundK 65 | sbis USBIN, USBMINUS 66 | rjmp foundK 67 | sbis USBIN, USBMINUS 68 | rjmp foundK 69 | #if USB_COUNT_SOF 70 | lds YL, usbSofCount 71 | inc YL 72 | sts usbSofCount, YL 73 | #endif /* USB_COUNT_SOF */ 74 | #ifdef USB_SOF_HOOK 75 | USB_SOF_HOOK 76 | #endif 77 | rjmp sofError 78 | foundK: ;[-12] 79 | ;{3, 5} after falling D- edge, average delay: 4 cycles [we want 5 for center sampling] 80 | ;we have 1 bit time for setup purposes, then sample again. Numbers in brackets 81 | ;are cycles from center of first sync (double K) bit after the instruction 82 | push r0 ;[-12] 83 | ; [---] ;[-11] 84 | push YH ;[-10] 85 | ; [---] ;[-9] 86 | lds YL, usbInputBufOffset;[-8] 87 | ; [---] ;[-7] 88 | clr YH ;[-6] 89 | subi YL, lo8(-(usbRxBuf));[-5] [rx loop init] 90 | sbci YH, hi8(-(usbRxBuf));[-4] [rx loop init] 91 | mov r0, x2 ;[-3] [rx loop init] 92 | sbis USBIN, USBMINUS ;[-2] we want two bits K (sample 2 cycles too early) 93 | rjmp haveTwoBitsK ;[-1] 94 | pop YH ;[0] undo the pushes from before 95 | pop r0 ;[2] 96 | rjmp waitForK ;[4] this was not the end of sync, retry 97 | ; The entire loop from waitForK until rjmp waitForK above must not exceed two 98 | ; bit times (= 22 cycles). 99 | 100 | ;---------------------------------------------------------------------------- 101 | ; push more registers and initialize values while we sample the first bits: 102 | ;---------------------------------------------------------------------------- 103 | haveTwoBitsK: ;[1] 104 | push shift ;[1] 105 | push x1 ;[3] 106 | push x2 ;[5] 107 | push x3 ;[7] 108 | ldi shift, 0xff ;[9] [rx loop init] 109 | ori x3, 0xff ;[10] [rx loop init] == ser x3, clear zero flag 110 | 111 | in x1, USBIN ;[11] <-- sample bit 0 112 | bst x1, USBMINUS ;[12] 113 | bld shift, 0 ;[13] 114 | push x4 ;[14] == phase 115 | ; [---] ;[15] 116 | push cnt ;[16] 117 | ; [---] ;[17] 118 | ldi phase, 0 ;[18] [rx loop init] 119 | ldi cnt, USB_BUFSIZE;[19] [rx loop init] 120 | rjmp rxbit1 ;[20] 121 | ; [---] ;[21] 122 | 123 | ;---------------------------------------------------------------------------- 124 | ; Receiver loop (numbers in brackets are cycles within byte after instr) 125 | ;---------------------------------------------------------------------------- 126 | /* 127 | byte oriented operations done during loop: 128 | bit 0: store data 129 | bit 1: SE0 check 130 | bit 2: overflow check 131 | bit 3: catch up 132 | bit 4: rjmp to achieve conditional jump range 133 | bit 5: PLL 134 | bit 6: catch up 135 | bit 7: jump, fixup bitstuff 136 | ; 87 [+ 2] cycles 137 | ------------------------------------------------------------------ 138 | */ 139 | continueWithBit5: 140 | in x2, USBIN ;[055] <-- bit 5 141 | eor r0, x2 ;[056] 142 | or phase, r0 ;[057] 143 | sbrc phase, USBMINUS ;[058] 144 | lpm ;[059] optional nop3; modifies r0 145 | in phase, USBIN ;[060] <-- phase 146 | eor x1, x2 ;[061] 147 | bst x1, USBMINUS ;[062] 148 | bld shift, 5 ;[063] 149 | andi shift, 0x3f ;[064] 150 | in x1, USBIN ;[065] <-- bit 6 151 | breq unstuff5 ;[066] *** unstuff escape 152 | eor phase, x1 ;[067] 153 | eor x2, x1 ;[068] 154 | bst x2, USBMINUS ;[069] 155 | bld shift, 6 ;[070] 156 | didUnstuff6: ;[ ] 157 | in r0, USBIN ;[071] <-- phase 158 | cpi shift, 0x02 ;[072] 159 | brlo unstuff6 ;[073] *** unstuff escape 160 | didUnstuff5: ;[ ] 161 | nop2 ;[074] 162 | ; [---] ;[075] 163 | in x2, USBIN ;[076] <-- bit 7 164 | eor x1, x2 ;[077] 165 | bst x1, USBMINUS ;[078] 166 | bld shift, 7 ;[079] 167 | didUnstuff7: ;[ ] 168 | eor r0, x2 ;[080] 169 | or phase, r0 ;[081] 170 | in r0, USBIN ;[082] <-- phase 171 | cpi shift, 0x04 ;[083] 172 | brsh rxLoop ;[084] 173 | ; [---] ;[085] 174 | unstuff7: ;[ ] 175 | andi x3, ~0x80 ;[085] 176 | ori shift, 0x80 ;[086] 177 | in x2, USBIN ;[087] <-- sample stuffed bit 7 178 | nop ;[088] 179 | rjmp didUnstuff7 ;[089] 180 | ; [---] ;[090] 181 | ;[080] 182 | 183 | unstuff5: ;[067] 184 | eor phase, x1 ;[068] 185 | andi x3, ~0x20 ;[069] 186 | ori shift, 0x20 ;[070] 187 | in r0, USBIN ;[071] <-- phase 188 | mov x2, x1 ;[072] 189 | nop ;[073] 190 | nop2 ;[074] 191 | ; [---] ;[075] 192 | in x1, USBIN ;[076] <-- bit 6 193 | eor r0, x1 ;[077] 194 | or phase, r0 ;[078] 195 | eor x2, x1 ;[079] 196 | bst x2, USBMINUS ;[080] 197 | bld shift, 6 ;[081] no need to check bitstuffing, we just had one 198 | in r0, USBIN ;[082] <-- phase 199 | rjmp didUnstuff5 ;[083] 200 | ; [---] ;[084] 201 | ;[074] 202 | 203 | unstuff6: ;[074] 204 | andi x3, ~0x40 ;[075] 205 | in x1, USBIN ;[076] <-- bit 6 again 206 | ori shift, 0x40 ;[077] 207 | nop2 ;[078] 208 | ; [---] ;[079] 209 | rjmp didUnstuff6 ;[080] 210 | ; [---] ;[081] 211 | ;[071] 212 | 213 | unstuff0: ;[013] 214 | eor r0, x2 ;[014] 215 | or phase, r0 ;[015] 216 | andi x2, USBMASK ;[016] check for SE0 217 | in r0, USBIN ;[017] <-- phase 218 | breq didUnstuff0 ;[018] direct jump to se0 would be too long 219 | andi x3, ~0x01 ;[019] 220 | ori shift, 0x01 ;[020] 221 | mov x1, x2 ;[021] mov existing sample 222 | in x2, USBIN ;[022] <-- bit 1 again 223 | rjmp didUnstuff0 ;[023] 224 | ; [---] ;[024] 225 | ;[014] 226 | 227 | unstuff1: ;[024] 228 | eor r0, x1 ;[025] 229 | or phase, r0 ;[026] 230 | andi x3, ~0x02 ;[027] 231 | in r0, USBIN ;[028] <-- phase 232 | ori shift, 0x02 ;[029] 233 | mov x2, x1 ;[030] 234 | rjmp didUnstuff1 ;[031] 235 | ; [---] ;[032] 236 | ;[022] 237 | 238 | unstuff2: ;[035] 239 | eor r0, x2 ;[036] 240 | or phase, r0 ;[037] 241 | andi x3, ~0x04 ;[038] 242 | in r0, USBIN ;[039] <-- phase 243 | ori shift, 0x04 ;[040] 244 | mov x1, x2 ;[041] 245 | rjmp didUnstuff2 ;[042] 246 | ; [---] ;[043] 247 | ;[033] 248 | 249 | unstuff3: ;[043] 250 | in x2, USBIN ;[044] <-- bit 3 again 251 | eor r0, x2 ;[045] 252 | or phase, r0 ;[046] 253 | andi x3, ~0x08 ;[047] 254 | ori shift, 0x08 ;[048] 255 | nop ;[049] 256 | in r0, USBIN ;[050] <-- phase 257 | rjmp didUnstuff3 ;[051] 258 | ; [---] ;[052] 259 | ;[042] 260 | 261 | unstuff4: ;[053] 262 | andi x3, ~0x10 ;[054] 263 | in x1, USBIN ;[055] <-- bit 4 again 264 | ori shift, 0x10 ;[056] 265 | rjmp didUnstuff4 ;[057] 266 | ; [---] ;[058] 267 | ;[048] 268 | 269 | rxLoop: ;[085] 270 | eor x3, shift ;[086] reconstruct: x3 is 0 at bit locations we changed, 1 at others 271 | in x1, USBIN ;[000] <-- bit 0 272 | st y+, x3 ;[001] 273 | ; [---] ;[002] 274 | eor r0, x1 ;[003] 275 | or phase, r0 ;[004] 276 | eor x2, x1 ;[005] 277 | in r0, USBIN ;[006] <-- phase 278 | ser x3 ;[007] 279 | bst x2, USBMINUS ;[008] 280 | bld shift, 0 ;[009] 281 | andi shift, 0xf9 ;[010] 282 | rxbit1: ;[ ] 283 | in x2, USBIN ;[011] <-- bit 1 284 | breq unstuff0 ;[012] *** unstuff escape 285 | andi x2, USBMASK ;[013] SE0 check for bit 1 286 | didUnstuff0: ;[ ] Z only set if we detected SE0 in bitstuff 287 | breq se0 ;[014] 288 | eor r0, x2 ;[015] 289 | or phase, r0 ;[016] 290 | in r0, USBIN ;[017] <-- phase 291 | eor x1, x2 ;[018] 292 | bst x1, USBMINUS ;[019] 293 | bld shift, 1 ;[020] 294 | andi shift, 0xf3 ;[021] 295 | didUnstuff1: ;[ ] 296 | in x1, USBIN ;[022] <-- bit 2 297 | breq unstuff1 ;[023] *** unstuff escape 298 | eor r0, x1 ;[024] 299 | or phase, r0 ;[025] 300 | subi cnt, 1 ;[026] overflow check 301 | brcs overflow ;[027] 302 | in r0, USBIN ;[028] <-- phase 303 | eor x2, x1 ;[029] 304 | bst x2, USBMINUS ;[030] 305 | bld shift, 2 ;[031] 306 | andi shift, 0xe7 ;[032] 307 | didUnstuff2: ;[ ] 308 | in x2, USBIN ;[033] <-- bit 3 309 | breq unstuff2 ;[034] *** unstuff escape 310 | eor r0, x2 ;[035] 311 | or phase, r0 ;[036] 312 | eor x1, x2 ;[037] 313 | bst x1, USBMINUS ;[038] 314 | in r0, USBIN ;[039] <-- phase 315 | bld shift, 3 ;[040] 316 | andi shift, 0xcf ;[041] 317 | didUnstuff3: ;[ ] 318 | breq unstuff3 ;[042] *** unstuff escape 319 | nop ;[043] 320 | in x1, USBIN ;[044] <-- bit 4 321 | eor x2, x1 ;[045] 322 | bst x2, USBMINUS ;[046] 323 | bld shift, 4 ;[047] 324 | didUnstuff4: ;[ ] 325 | eor r0, x1 ;[048] 326 | or phase, r0 ;[049] 327 | in r0, USBIN ;[050] <-- phase 328 | andi shift, 0x9f ;[051] 329 | breq unstuff4 ;[052] *** unstuff escape 330 | rjmp continueWithBit5;[053] 331 | ; [---] ;[054] 332 | 333 | macro POP_STANDARD ; 16 cycles 334 | pop cnt 335 | pop x4 336 | pop x3 337 | pop x2 338 | pop x1 339 | pop shift 340 | pop YH 341 | pop r0 342 | endm 343 | macro POP_RETI ; 5 cycles 344 | pop YL 345 | out SREG, YL 346 | pop YL 347 | endm 348 | 349 | #include "asmcommon.inc" 350 | 351 | 352 | ; USB spec says: 353 | ; idle = J 354 | ; J = (D+ = 0), (D- = 1) 355 | ; K = (D+ = 1), (D- = 0) 356 | ; Spec allows 7.5 bit times from EOP to SOP for replies 357 | 358 | bitstuff7: 359 | eor x1, x4 ;[4] 360 | ldi x2, 0 ;[5] 361 | nop2 ;[6] C is zero (brcc) 362 | rjmp didStuff7 ;[8] 363 | 364 | bitstuffN: 365 | eor x1, x4 ;[5] 366 | ldi x2, 0 ;[6] 367 | lpm ;[7] 3 cycle NOP, modifies r0 368 | out USBOUT, x1 ;[10] <-- out 369 | rjmp didStuffN ;[0] 370 | 371 | #define bitStatus x3 372 | 373 | sendNakAndReti: 374 | ldi cnt, USBPID_NAK ;[-19] 375 | rjmp sendCntAndReti ;[-18] 376 | sendAckAndReti: 377 | ldi cnt, USBPID_ACK ;[-17] 378 | sendCntAndReti: 379 | mov r0, cnt ;[-16] 380 | ldi YL, 0 ;[-15] R0 address is 0 381 | ldi YH, 0 ;[-14] 382 | ldi cnt, 2 ;[-13] 383 | ; rjmp usbSendAndReti fallthrough 384 | 385 | ;usbSend: 386 | ;pointer to data in 'Y' 387 | ;number of bytes in 'cnt' -- including sync byte [range 2 ... 12] 388 | ;uses: x1...x4, shift, cnt, Y 389 | ;Numbers in brackets are time since first bit of sync pattern is sent 390 | usbSendAndReti: ; 12 cycles until SOP 391 | in x2, USBDDR ;[-12] 392 | ori x2, USBMASK ;[-11] 393 | sbi USBOUT, USBMINUS;[-10] prepare idle state; D+ and D- must have been 0 (no pullups) 394 | in x1, USBOUT ;[-8] port mirror for tx loop 395 | out USBDDR, x2 ;[-7] <- acquire bus 396 | ; need not init x2 (bitstuff history) because sync starts with 0 397 | ldi x4, USBMASK ;[-6] exor mask 398 | ldi shift, 0x80 ;[-5] sync byte is first byte sent 399 | ldi bitStatus, 0xff ;[-4] init bit loop counter, works for up to 12 bytes 400 | byteloop: 401 | bitloop: 402 | sbrs shift, 0 ;[8] [-3] 403 | eor x1, x4 ;[9] [-2] 404 | out USBOUT, x1 ;[10] [-1] <-- out 405 | ror shift ;[0] 406 | ror x2 ;[1] 407 | didStuffN: 408 | cpi x2, 0xfc ;[2] 409 | brcc bitstuffN ;[3] 410 | nop ;[4] 411 | subi bitStatus, 37 ;[5] 256 / 7 ~=~ 37 412 | brcc bitloop ;[6] when we leave the loop, bitStatus has almost the initial value 413 | sbrs shift, 0 ;[7] 414 | eor x1, x4 ;[8] 415 | ror shift ;[9] 416 | didStuff7: 417 | out USBOUT, x1 ;[10] <-- out 418 | ror x2 ;[0] 419 | cpi x2, 0xfc ;[1] 420 | brcc bitstuff7 ;[2] 421 | ld shift, y+ ;[3] 422 | dec cnt ;[5] 423 | brne byteloop ;[6] 424 | ;make SE0: 425 | cbr x1, USBMASK ;[7] prepare SE0 [spec says EOP may be 21 to 25 cycles] 426 | lds x2, usbNewDeviceAddr;[8] 427 | lsl x2 ;[10] we compare with left shifted address 428 | out USBOUT, x1 ;[11] <-- out SE0 -- from now 2 bits = 22 cycles until bus idle 429 | ;2006-03-06: moved transfer of new address to usbDeviceAddr from C-Code to asm: 430 | ;set address only after data packet was sent, not after handshake 431 | subi YL, 2 ;[0] Only assign address on data packets, not ACK/NAK in r0 432 | sbci YH, 0 ;[1] 433 | breq skipAddrAssign ;[2] 434 | sts usbDeviceAddr, x2; if not skipped: SE0 is one cycle longer 435 | skipAddrAssign: 436 | ;end of usbDeviceAddress transfer 437 | ldi x2, 1< 13.333333 cycles per bit, 106.666667 cycles per byte 37 | ; Numbers in brackets are clocks counted from center of last sync bit 38 | ; when instruction starts 39 | ;register use in receive loop: 40 | ; shift assembles the byte currently being received 41 | ; x1 holds the D+ and D- line state 42 | ; x2 holds the previous line state 43 | ; x4 (leap) is used to add a leap cycle once every three bytes received 44 | ; X3 (leap2) is used to add a leap cycle once every three stuff bits received 45 | ; bitcnt is used to determine when a stuff bit is due 46 | ; cnt holds the number of bytes left in the receive buffer 47 | 48 | USB_INTR_VECTOR: 49 | ;order of registers pushed: YL, SREG YH, [sofError], bitcnt, shift, x1, x2, x3, x4, cnt 50 | push YL ;[-28] push only what is necessary to sync with edge ASAP 51 | in YL, SREG ;[-26] 52 | push YL ;[-25] 53 | push YH ;[-23] 54 | ;---------------------------------------------------------------------------- 55 | ; Synchronize with sync pattern: 56 | ;---------------------------------------------------------------------------- 57 | ;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K] 58 | ;sync up with J to K edge during sync pattern -- use fastest possible loops 59 | ;The first part waits at most 1 bit long since we must be in sync pattern. 60 | ;YL is guarenteed to be < 0x80 because I flag is clear. When we jump to 61 | ;waitForJ, ensure that this prerequisite is met. 62 | waitForJ: 63 | inc YL 64 | sbis USBIN, USBMINUS 65 | brne waitForJ ; just make sure we have ANY timeout 66 | waitForK: 67 | ;The following code results in a sampling window of < 1/4 bit which meets the spec. 68 | sbis USBIN, USBMINUS ;[-19] 69 | rjmp foundK ;[-18] 70 | sbis USBIN, USBMINUS 71 | rjmp foundK 72 | sbis USBIN, USBMINUS 73 | rjmp foundK 74 | sbis USBIN, USBMINUS 75 | rjmp foundK 76 | sbis USBIN, USBMINUS 77 | rjmp foundK 78 | sbis USBIN, USBMINUS 79 | rjmp foundK 80 | sbis USBIN, USBMINUS 81 | rjmp foundK 82 | sbis USBIN, USBMINUS 83 | rjmp foundK 84 | sbis USBIN, USBMINUS 85 | rjmp foundK 86 | #if USB_COUNT_SOF 87 | lds YL, usbSofCount 88 | inc YL 89 | sts usbSofCount, YL 90 | #endif /* USB_COUNT_SOF */ 91 | #ifdef USB_SOF_HOOK 92 | USB_SOF_HOOK 93 | #endif 94 | rjmp sofError 95 | foundK: ;[-16] 96 | ;{3, 5} after falling D- edge, average delay: 4 cycles 97 | ;bit0 should be at 34 for center sampling. Currently at 4 so 30 cylces till bit 0 sample 98 | ;use 1 bit time for setup purposes, then sample again. Numbers in brackets 99 | ;are cycles from center of first sync (double K) bit after the instruction 100 | push bitcnt ;[-16] 101 | ; [---] ;[-15] 102 | lds YL, usbInputBufOffset;[-14] 103 | ; [---] ;[-13] 104 | clr YH ;[-12] 105 | subi YL, lo8(-(usbRxBuf));[-11] [rx loop init] 106 | sbci YH, hi8(-(usbRxBuf));[-10] [rx loop init] 107 | push shift ;[-9] 108 | ; [---] ;[-8] 109 | ldi shift,0x40 ;[-7] set msb to "1" so processing bit7 can be detected 110 | nop2 ;[-6] 111 | ; [---] ;[-5] 112 | ldi bitcnt, 5 ;[-4] [rx loop init] 113 | sbis USBIN, USBMINUS ;[-3] we want two bits K (sample 3 cycles too early) 114 | rjmp haveTwoBitsK ;[-2] 115 | pop shift ;[-1] undo the push from before 116 | pop bitcnt ;[1] 117 | rjmp waitForK ;[3] this was not the end of sync, retry 118 | ; The entire loop from waitForK until rjmp waitForK above must not exceed two 119 | ; bit times (= 27 cycles). 120 | 121 | ;---------------------------------------------------------------------------- 122 | ; push more registers and initialize values while we sample the first bits: 123 | ;---------------------------------------------------------------------------- 124 | haveTwoBitsK: 125 | push x1 ;[0] 126 | push x2 ;[2] 127 | push x3 ;[4] (leap2) 128 | ldi leap2, 0x55 ;[6] add leap cycle on 2nd,5th,8th,... stuff bit 129 | push x4 ;[7] == leap 130 | ldi leap, 0x55 ;[9] skip leap cycle on 2nd,5th,8th,... byte received 131 | push cnt ;[10] 132 | ldi cnt, USB_BUFSIZE ;[12] [rx loop init] 133 | ldi x2, 1< 38 | #ifndef __IAR_SYSTEMS_ASM__ 39 | # include 40 | #endif 41 | 42 | #define __attribute__(arg) /* not supported on IAR */ 43 | 44 | #ifdef __IAR_SYSTEMS_ASM__ 45 | # define __ASSEMBLER__ /* IAR does not define standard macro for asm */ 46 | #endif 47 | 48 | #ifdef __HAS_ELPM__ 49 | # define PROGMEM __farflash 50 | #else 51 | # define PROGMEM __flash 52 | #endif 53 | 54 | #define USB_READ_FLASH(addr) (*(PROGMEM char *)(addr)) 55 | 56 | /* The following definitions are not needed by the driver, but may be of some 57 | * help if you port a gcc based project to IAR. 58 | */ 59 | #define cli() __disable_interrupt() 60 | #define sei() __enable_interrupt() 61 | #define wdt_reset() __watchdog_reset() 62 | #define _BV(x) (1 << (x)) 63 | 64 | /* assembler compatibility macros */ 65 | #define nop2 rjmp $+2 /* jump to next instruction */ 66 | #define XL r26 67 | #define XH r27 68 | #define YL r28 69 | #define YH r29 70 | #define ZL r30 71 | #define ZH r31 72 | #define lo8(x) LOW(x) 73 | #define hi8(x) (((x)>>8) & 0xff) /* not HIGH to allow XLINK to make a proper range check */ 74 | 75 | /* Depending on the device you use, you may get problems with the way usbdrv.h 76 | * handles the differences between devices. Since IAR does not use #defines 77 | * for MCU registers, we can't check for the existence of a particular 78 | * register with an #ifdef. If the autodetection mechanism fails, include 79 | * definitions for the required USB_INTR_* macros in your usbconfig.h. See 80 | * usbconfig-prototype.h and usbdrv.h for details. 81 | */ 82 | 83 | /* ------------------------------------------------------------------------- */ 84 | #elif __CODEVISIONAVR__ /* check for CodeVision AVR */ 85 | /* ------------------------------------------------------------------------- */ 86 | /* This port is not working (yet) */ 87 | 88 | /* #define F_CPU _MCU_CLOCK_FREQUENCY_ seems to be defined automatically */ 89 | 90 | #include 91 | #include 92 | 93 | #define __attribute__(arg) /* not supported on IAR */ 94 | 95 | #define PROGMEM __flash 96 | #define USB_READ_FLASH(addr) (*(PROGMEM char *)(addr)) 97 | 98 | #ifndef __ASSEMBLER__ 99 | static inline void cli(void) 100 | { 101 | #asm("cli"); 102 | } 103 | static inline void sei(void) 104 | { 105 | #asm("sei"); 106 | } 107 | #endif 108 | #define _delay_ms(t) delay_ms(t) 109 | #define _BV(x) (1 << (x)) 110 | #define USB_CFG_USE_SWITCH_STATEMENT 1 /* macro for if() cascase fails for unknown reason */ 111 | 112 | #define macro .macro 113 | #define endm .endmacro 114 | #define nop2 rjmp .+0 /* jump to next instruction */ 115 | 116 | /* ------------------------------------------------------------------------- */ 117 | #else /* default development environment is avr-gcc/avr-libc */ 118 | /* ------------------------------------------------------------------------- */ 119 | 120 | #include 121 | #ifdef __ASSEMBLER__ 122 | # define _VECTOR(N) __vector_ ## N /* io.h does not define this for asm */ 123 | #else 124 | # include 125 | #endif 126 | 127 | #if USB_CFG_DRIVER_FLASH_PAGE 128 | # define USB_READ_FLASH(addr) pgm_read_byte_far(((long)USB_CFG_DRIVER_FLASH_PAGE << 16) | (long)(addr)) 129 | #else 130 | # define USB_READ_FLASH(addr) pgm_read_byte(addr) 131 | #endif 132 | 133 | #define macro .macro 134 | #define endm .endm 135 | #define nop2 rjmp .+0 /* jump to next instruction */ 136 | 137 | #endif /* development environment */ 138 | 139 | /* for conveniecne, ensure that PRG_RDB exists */ 140 | #ifndef PRG_RDB 141 | # define PRG_RDB(addr) USB_READ_FLASH(addr) 142 | #endif 143 | #endif /* __usbportability_h_INCLUDED__ */ 144 | -------------------------------------------------------------------------------- /resources/enclosure-labels/top-label.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dilshan/i2c-test-terminal/7def072ba9c85831d2352408248afc9305152494/resources/enclosure-labels/top-label.pdf -------------------------------------------------------------------------------- /resources/i2c-tester-prototype-enc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dilshan/i2c-test-terminal/7def072ba9c85831d2352408248afc9305152494/resources/i2c-tester-prototype-enc.jpg -------------------------------------------------------------------------------- /resources/i2c-tester-sample-connection.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dilshan/i2c-test-terminal/7def072ba9c85831d2352408248afc9305152494/resources/i2c-tester-sample-connection.fzz -------------------------------------------------------------------------------- /resources/i2c-tester-sample-connection.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dilshan/i2c-test-terminal/7def072ba9c85831d2352408248afc9305152494/resources/i2c-tester-sample-connection.jpg -------------------------------------------------------------------------------- /terminal/src/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "docuproc.h": "c", 4 | "cmdproc.h": "c" 5 | } 6 | } -------------------------------------------------------------------------------- /terminal/src/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -I. -ludev -lreadline -lpthread 3 | 4 | DEPS = main.h common.h strdef.h termutil.h docuproc.h cmdproc.h strdoc.h 5 | 6 | OBJ = termutil.o docuproc.o cmdproc.o main.o 7 | 8 | %.o: %.c $(DEPS) 9 | $(CC) -c -o $@ $< $(CFLAGS) 10 | 11 | i2cterminal: $(OBJ) 12 | $(CC) -o $@ $^ $(CFLAGS) 13 | 14 | .PHONY: clean 15 | 16 | clean: 17 | rm -f *.o i2cterminal -------------------------------------------------------------------------------- /terminal/src/cmdproc.c: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------------- 2 | // I2C Test Terminal - Command Processor. 3 | // 4 | // Copyright (c) 2021 Dilshan R Jayakody [jayakody2000lk@gmail.com]. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | //---------------------------------------------------------------------------------- 24 | 25 | #include "cmdproc.h" 26 | #include "termutil.h" 27 | #include "strdef.h" 28 | #include "common.h" 29 | #include "docuproc.h" 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #define RELEASE_STR(x) free(x);x=NULL 37 | 38 | #define MAX_TOKEN_COUNT 2 39 | 40 | // List of commands available with I2C terminal. 41 | const char *cmdList[] = {"help", "init", "start", "stop", "write", "write-address", "read", "output-voltage", "reset", "exit"}; 42 | 43 | char *cmdGenerator(const char *text, int state) 44 | { 45 | static int listIndex, len; 46 | const char *name; 47 | 48 | if (!state) 49 | { 50 | listIndex = 0; 51 | len = strlen(text); 52 | } 53 | 54 | // Looking for matching commands for the given name. 55 | while (name = cmdList[listIndex]) 56 | { 57 | listIndex++; 58 | if (strncmp(name, text, len) == 0) 59 | { 60 | return strdup (name); 61 | } 62 | } 63 | 64 | // Unable to find matching entry from the list. 65 | return ((char *) NULL); 66 | } 67 | 68 | static char **cmdCompletion(const char *text, int start, int end) 69 | { 70 | // Avoid adding spaces to the end of the matching word. 71 | rl_completion_append_character = '\0'; 72 | 73 | char **matches = (char **) NULL; 74 | if (start == 0) 75 | { 76 | matches = rl_completion_matches((char *) text, &cmdGenerator); 77 | } 78 | 79 | return matches; 80 | } 81 | 82 | unsigned char *createUSBBuffer(unsigned char cmd, unsigned char data) 83 | { 84 | unsigned char* usbBuffer = calloc(USB_SET_COMMAND_BUFFER_SIZE, 1); 85 | usbBuffer[0] = SYS_SIGNATURE; 86 | usbBuffer[1] = cmd; 87 | usbBuffer[2] = data; 88 | usbBuffer[3] = SYS_END_SIGNATURE; 89 | 90 | return usbBuffer; 91 | } 92 | 93 | EXEC_STATUS getSpeed(char **strBuffer, unsigned char *out) 94 | { 95 | long convNum; 96 | 97 | if((*strBuffer)[0] == '\0') 98 | { 99 | // String buffer is empty. 100 | printErrorMsg(CMD_MSG_PARAMETER_MISSING); 101 | return EXEC_FAIL; 102 | } 103 | 104 | convNum = strtol((*strBuffer), NULL, 0); 105 | if((convNum == 100) || (convNum == 250) || (convNum == 400)) 106 | { 107 | // Convert speed value into byte which identify by the firmware. 108 | switch(convNum) 109 | { 110 | case 100: 111 | *out = TWI_COM_SPEED_100; 112 | break; 113 | case 250: 114 | *out = TWI_COM_SPEED_250; 115 | break; 116 | case 400: 117 | *out = TWI_COM_SPEED_400; 118 | break; 119 | } 120 | } 121 | else 122 | { 123 | // Unsupported I2C speed value. 124 | printErrorMsg(CMD_MSG_SPEED_UNSUPPORT); 125 | return EXEC_FAIL; 126 | } 127 | 128 | return EXEC_SUCCESS; 129 | } 130 | 131 | EXEC_STATUS getByte(char **strBuffer, unsigned char *out) 132 | { 133 | long convNum; 134 | 135 | if((*strBuffer)[0] == '\0') 136 | { 137 | // String buffer is empty. 138 | printErrorMsg(CMD_MSG_PARAMETER_MISSING); 139 | return EXEC_FAIL; 140 | } 141 | 142 | convNum = strtol((*strBuffer), NULL, 0); 143 | if((convNum < 0) || (convNum > 0xFF)) 144 | { 145 | // Value out-of-range! 146 | printErrorMsg(CMD_MSG_OUTOF_RANGE); 147 | return EXEC_FAIL; 148 | } 149 | 150 | *out = (unsigned char)convNum; 151 | return EXEC_SUCCESS; 152 | } 153 | 154 | EXEC_STATUS getVoltageLevel(char **strBuffer, unsigned char *out) 155 | { 156 | if((*strBuffer)[0] == '\0') 157 | { 158 | // String buffer is empty. 159 | printErrorMsg(CMD_MSG_PARAMETER_MISSING); 160 | return EXEC_FAIL; 161 | } 162 | 163 | if((strcmp((*strBuffer), "3.3") == 0) || (strcmp((*strBuffer), "3.3V") == 0) || (strcmp((*strBuffer), "3.3v") == 0)) 164 | { 165 | // Activate 3.3V I2C output voltage. 166 | *out = I2C_OUTPUT_3V3; 167 | return EXEC_SUCCESS; 168 | } 169 | else if((strcmp((*strBuffer), "5") == 0) || (strcmp((*strBuffer), "5.0V") == 0) || (strcmp((*strBuffer), "5.0v") == 0) 170 | || (strcmp((*strBuffer), "5v") == 0) || (strcmp((*strBuffer), "5V") == 0)) 171 | { 172 | // Activate 5.0V I2C output voltage. 173 | *out = I2C_OUTPUT_5V; 174 | return EXEC_SUCCESS; 175 | } 176 | 177 | // Unsupported read flag. 178 | printErrorMsg(CMD_PARAM_INVALID_VOLTAGE); 179 | return EXEC_FAIL; 180 | } 181 | 182 | EXEC_STATUS getReadStatus(char **strBuffer, unsigned char *out) 183 | { 184 | if((*strBuffer)[0] == '\0') 185 | { 186 | // String buffer is empty. 187 | printErrorMsg(CMD_MSG_PARAMETER_MISSING); 188 | return EXEC_FAIL; 189 | } 190 | 191 | if((strcmp((*strBuffer), "ack") == 0) || (strcmp((*strBuffer), "1") == 0)) 192 | { 193 | // Perform read and send ACK to the device. 194 | *out = 1; 195 | return EXEC_SUCCESS; 196 | } 197 | else if((strcmp((*strBuffer), "nack") == 0) || (strcmp((*strBuffer), "0") == 0)) 198 | { 199 | // Perform read and send NACK to the device. 200 | *out = 0; 201 | return EXEC_SUCCESS; 202 | } 203 | 204 | // Unsupported read flag. 205 | printErrorMsg(CMD_PARAM_READ_UNSUPPORTED); 206 | return EXEC_FAIL; 207 | } 208 | 209 | unsigned char getCommand(unsigned char **cmdParam) 210 | { 211 | char *inCmd = NULL; 212 | char *token = NULL; 213 | char *helpId = NULL; 214 | unsigned char returnStatus = CMD_STATUS_OK; 215 | char *cmdData[MAX_TOKEN_COUNT]; 216 | unsigned char tokenPos; 217 | unsigned char paramVal; 218 | 219 | *cmdParam = NULL; 220 | 221 | // Getting input command from the user. 222 | rl_attempted_completion_function = cmdCompletion; 223 | while ((inCmd = readline("> ")) != NULL) 224 | { 225 | if(inCmd[0] == '\0') 226 | { 227 | // Ignore empty input data buffer. 228 | RELEASE_STR(inCmd); 229 | continue; 230 | } 231 | else 232 | { 233 | // Add input command to the history list. 234 | add_history(inCmd); 235 | } 236 | 237 | // Process input commands. 238 | if(strcmp(inCmd, "exit") == 0) 239 | { 240 | // EXIT command. Terminate the I2C terminal. 241 | returnStatus = CMD_STATUS_EXIT; 242 | break; 243 | } 244 | 245 | // Extract tokens into char array. 246 | token = strtok(inCmd, " "); 247 | tokenPos = 0; 248 | while(token != NULL) 249 | { 250 | cmdData[tokenPos++] = token; 251 | token = strtok(NULL, " "); 252 | 253 | // Check for maximum token limit. 254 | if(tokenPos >= MAX_TOKEN_COUNT) 255 | { 256 | break; 257 | } 258 | } 259 | 260 | // Execute commands based on the token values. 261 | if(strcmp(cmdData[0], "help") == 0) 262 | { 263 | // If available get the help topic ID from the parameter. 264 | helpId = (tokenPos >= 2) ? cmdData[1] : NULL; 265 | showHelp(&helpId); 266 | 267 | // Flush help command and continue for the next input. 268 | RELEASE_STR(inCmd); 269 | continue; 270 | } 271 | else if(strcmp(cmdData[0], "init") == 0) 272 | { 273 | // I2C session initialize with given speed. 274 | if(tokenPos < 2) 275 | { 276 | // Required paramaters are missing. INIT 277 | printCommandError(CMD_MSG_PARAMETER_MISSING, cmdData[0]); 278 | RELEASE_STR(inCmd); 279 | continue; 280 | } 281 | 282 | if(getSpeed(&(cmdData[1]), ¶mVal) == EXEC_FAIL) 283 | { 284 | // Parameter value is invalid or not specified. 285 | RELEASE_STR(inCmd); 286 | continue; 287 | } 288 | 289 | // Create HID feature buffer to send to the device. 290 | *cmdParam = createUSBBuffer(USB_CMD_I2C_INIT, paramVal); 291 | break; 292 | } 293 | else if(strcmp(cmdData[0], "start") == 0) 294 | { 295 | // Send I2C start command. 296 | if(tokenPos > 1) 297 | { 298 | // Parameters are not required for this command. 299 | printWarningMsg(CMD_PARAM_IGNORE); 300 | } 301 | 302 | // Create HID feature buffer to send to the device. 303 | *cmdParam = createUSBBuffer(USB_CMD_I2C_START, 0x00); 304 | break; 305 | } 306 | else if(strcmp(cmdData[0], "stop") == 0) 307 | { 308 | // Send I2C stop command. 309 | if(tokenPos > 1) 310 | { 311 | // Parameters are not required for this command. 312 | printWarningMsg(CMD_PARAM_IGNORE); 313 | } 314 | 315 | // Create HID feature buffer to send to the device. 316 | *cmdParam = createUSBBuffer(USB_CMD_I2C_STOP, 0x00); 317 | break; 318 | } 319 | else if(strcmp(cmdData[0], "write") == 0) 320 | { 321 | // Write data into I2C bus. 322 | if(tokenPos < 2) 323 | { 324 | // Required paramaters are missing. WRITE 325 | printCommandError(CMD_MSG_PARAMETER_MISSING, cmdData[0]); 326 | RELEASE_STR(inCmd); 327 | continue; 328 | } 329 | 330 | if(getByte(&(cmdData[1]), ¶mVal) == EXEC_FAIL) 331 | { 332 | // Parameter value is invalid or not specified. 333 | RELEASE_STR(inCmd); 334 | continue; 335 | } 336 | 337 | // Create HID feature buffer to send to the device. 338 | *cmdParam = createUSBBuffer(USB_CMD_I2C_WRITE, paramVal); 339 | break; 340 | } 341 | else if(strcmp(cmdData[0], "write-address") == 0) 342 | { 343 | // Write device address and read/write flag into I2C bus. 344 | if(tokenPos < 2) 345 | { 346 | // Required paramaters are missing. WRITE-ADDRESS
347 | printCommandError(CMD_MSG_PARAMETER_MISSING, cmdData[0]); 348 | RELEASE_STR(inCmd); 349 | continue; 350 | } 351 | 352 | if(getByte(&(cmdData[1]), ¶mVal) == EXEC_FAIL) 353 | { 354 | // Parameter value is invalid or not specified. 355 | RELEASE_STR(inCmd); 356 | continue; 357 | } 358 | 359 | // Create HID feature buffer to send to the device. 360 | *cmdParam = createUSBBuffer(USB_CMD_I2C_WRITE_ADDR, paramVal); 361 | break; 362 | } 363 | else if(strcmp(cmdData[0], "read") == 0) 364 | { 365 | // Read data from slave device. 366 | if(tokenPos >= 2) 367 | { 368 | // ACK/NACK flag is specified by the user? 369 | if(getReadStatus(&(cmdData[1]), ¶mVal) == EXEC_FAIL) 370 | { 371 | // Parameter value is invalid or not specified. 372 | RELEASE_STR(inCmd); 373 | continue; 374 | } 375 | } 376 | else 377 | { 378 | // If paramater is not specified use NACK as default. 379 | paramVal = 0; 380 | } 381 | 382 | // Create HID feature buffer to send to the device. 383 | *cmdParam = createUSBBuffer(USB_CMD_I2C_READ, paramVal); 384 | break; 385 | } 386 | else if(strcmp(cmdData[0], "output-voltage") == 0) 387 | { 388 | // Set output voltage of the I2C device. 389 | if(tokenPos < 2) 390 | { 391 | // Required paramaters are missing. WRITE-ADDRESS
392 | printCommandError(CMD_MSG_PARAMETER_MISSING, cmdData[0]); 393 | RELEASE_STR(inCmd); 394 | continue; 395 | } 396 | 397 | if(getVoltageLevel(&(cmdData[1]), ¶mVal) == EXEC_FAIL) 398 | { 399 | // Parameter value is invalid or not specified. 400 | RELEASE_STR(inCmd); 401 | continue; 402 | } 403 | 404 | // Create HID feature buffer to send to the device. 405 | *cmdParam = createUSBBuffer(USB_CMD_SET_VOLTAGE, paramVal); 406 | break; 407 | } 408 | else if(strcmp(cmdData[0], "reset") == 0) 409 | { 410 | // Reset slave device and I2C registers to default values. 411 | if(tokenPos > 1) 412 | { 413 | // Parameters are not required for this command. 414 | printWarningMsg(CMD_PARAM_IGNORE); 415 | } 416 | 417 | // Create HID feature buffer to send to the device. 418 | *cmdParam = createUSBBuffer(USB_CMD_RESET, 0x00); 419 | break; 420 | } 421 | else 422 | { 423 | // Unknown command! 424 | printCommandError(CMD_MSG_UNKNOWN, cmdData[0]); 425 | RELEASE_STR(inCmd); 426 | continue; 427 | } 428 | } 429 | 430 | // Release input buffer. 431 | if(inCmd != NULL) 432 | { 433 | RELEASE_STR(inCmd); 434 | } 435 | 436 | return returnStatus; 437 | } -------------------------------------------------------------------------------- /terminal/src/cmdproc.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------------- 2 | // I2C Test Terminal - Command Processor. 3 | // 4 | // Copyright (c) 2021 Dilshan R Jayakody [jayakody2000lk@gmail.com]. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | //---------------------------------------------------------------------------------- 24 | 25 | #ifndef I2C_TERMINAL_COMMOND_PROCESSOR 26 | #define I2C_TERMINAL_COMMOND_PROCESSOR 27 | 28 | #define CMD_STATUS_OK 0 29 | #define CMD_STATUS_EXIT 1 30 | 31 | unsigned char *createUSBBuffer(unsigned char cmd, unsigned char data); 32 | unsigned char getCommand(unsigned char **cmdParam); 33 | 34 | #endif /* I2C_TERMINAL_COMMOND_PROCESSOR */ -------------------------------------------------------------------------------- /terminal/src/common.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------------- 2 | // I2C Test Terminal - Common Header File / Configuration Settings. 3 | // 4 | // Copyright (c) 2021 Dilshan R Jayakody [jayakody2000lk@gmail.com]. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | //---------------------------------------------------------------------------------- 24 | 25 | #ifndef I2C_TERMINAL_COMMON 26 | #define I2C_TERMINAL_COMMON 27 | 28 | typedef unsigned char EXEC_STATUS; 29 | 30 | struct UsbComData 31 | { 32 | unsigned char* comData; 33 | int deviceHandler; 34 | }; 35 | 36 | #define EXEC_SUCCESS 0x00 37 | #define EXEC_FAIL 0xFF 38 | 39 | #define SYS_SIGNATURE 0x5D 40 | #define SYS_END_SIGNATURE 0x5A 41 | 42 | #define USB_CMD_NONE 0x00 43 | #define USB_CMD_I2C_INIT 0x01 44 | #define USB_CMD_I2C_START 0x02 45 | #define USB_CMD_I2C_STOP 0x03 46 | #define USB_CMD_I2C_WRITE_ADDR 0x04 47 | #define USB_CMD_I2C_WRITE 0x05 48 | #define USB_CMD_I2C_READ 0x06 49 | #define USB_CMD_SET_VOLTAGE 0x07 50 | #define USB_CMD_GET_VOLTAGE 0x08 51 | #define USB_CMD_RESET 0x09 52 | 53 | #define TWI_COM_SPEED_100 0 // 100kHz 54 | #define TWI_COM_SPEED_250 1 // 250kHz 55 | #define TWI_COM_SPEED_400 2 // 400kHz 56 | 57 | #define USB_SET_COMMAND_BUFFER_SIZE 64 58 | #define USB_GET_DATA_BUFFER_SIZE 64 59 | 60 | #define RET_SUCCESS 0x00 61 | #define RET_PENDING 0x01 62 | #define RET_UNKNOWN 0x02 63 | #define RET_TIMEOUT_FAIL 0xFF 64 | 65 | #define I2C_OUTPUT_5V 0x01 66 | #define I2C_OUTPUT_3V3 0x02 67 | 68 | #endif /* I2C_TERMINAL_COMMON */ -------------------------------------------------------------------------------- /terminal/src/docuproc.c: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------------- 2 | // I2C Test Terminal - Help / Documentation Processor. 3 | // 4 | // Copyright (c) 2021 Dilshan R Jayakody [jayakody2000lk@gmail.com]. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | //---------------------------------------------------------------------------------- 24 | 25 | #include "docuproc.h" 26 | #include "termutil.h" 27 | #include "strdoc.h" 28 | 29 | #include 30 | #include 31 | 32 | void showGeneralHelp() 33 | { 34 | printHelp(HELP_GEN_ABOUT); 35 | printHelp(HELP_GEN_CMD_HELP); 36 | printHelp(HELP_GEN_CMD_INIT); 37 | printHelp(HELP_GEN_CMD_START); 38 | printHelp(HELP_GEN_CMD_STOP); 39 | printHelp(HELP_GEN_CMD_WRITE); 40 | printHelp(HELP_GEN_CMD_WRITE_ADDR); 41 | printHelp(HELP_GEN_CMD_READ); 42 | printHelp(HELP_GEN_CMD_OUT_VOLTAGE); 43 | printHelp(HELP_GEN_CMD_RESET); 44 | printHelp(HELP_GEN_CMD_EXIT); 45 | 46 | printHelp(HELP_USE_HELP1); 47 | printHelp(HELP_USE_HELP2); 48 | printHelp(HELP_USE_HELP3); 49 | 50 | printHelp(HELP_AUTO_COMPLETE1); 51 | printHelp(HELP_AUTO_COMPLETE2); 52 | 53 | printHelp(HELP_GITHUB_REF1); 54 | printHelp(HELP_GITHUB_REF2); 55 | } 56 | 57 | void showHelp(char **topicId) 58 | { 59 | if((topicId == NULL) || ((*topicId) == NULL) || (strcmp((*topicId), "help") == 0)) 60 | { 61 | // Parameter for the help command is not available. Show General help. 62 | showGeneralHelp(); 63 | } 64 | else 65 | { 66 | // Parameter is given with the help command. 67 | if(strcmp((*topicId), "init") == 0) 68 | { 69 | printHelpCmdFormat(HELP_INIT_FORMAT); 70 | printHelp(HELP_INIT_INTRO1); 71 | printHelp(HELP_INIT_INTRO2); 72 | 73 | printHelp(HELP_INIT_SPEED_100); 74 | printHelp(HELP_INIT_SPEED_250); 75 | printHelp(HELP_INIT_SPEED_400); 76 | 77 | printHelp(HELP_INIT_WARNING1); 78 | printHelp(HELP_INIT_WARNING2); 79 | } 80 | else if(strcmp((*topicId), "start") == 0) 81 | { 82 | printHelpCmdFormat(HELP_START_FORMAT); 83 | printHelp(HELP_START_INTRO1); 84 | printHelp(HELP_START_INTRO2); 85 | printHelp(HELP_START_INTRO3); 86 | } 87 | else if(strcmp((*topicId), "stop") == 0) 88 | { 89 | printHelpCmdFormat(HELP_STOP_FORMAT); 90 | printHelp(HELP_STOP_INTRO1); 91 | printHelp(HELP_STOP_INTRO2); 92 | } 93 | else if(strcmp((*topicId), "write") == 0) 94 | { 95 | printHelpCmdFormat(HELP_WRITE_FORMAT); 96 | printHelp(HELP_WRITE_INTRO1); 97 | printHelp(HELP_WRITE_INTRO2); 98 | printHelp(HELP_WRITE_INTRO3); 99 | } 100 | else if(strcmp((*topicId), "write-address") == 0) 101 | { 102 | printHelpCmdFormat(HELP_WRITE_ADDR_FORMAT); 103 | printHelp(HELP_WRITE_ADDR_INTRO1); 104 | printHelp(HELP_WRITE_ADDR_INTRO2); 105 | printHelp(HELP_WRITE_ADDR_INTRO3); 106 | printHelp(HELP_WRITE_ADDR_INTRO4); 107 | } 108 | else if(strcmp((*topicId), "read") == 0) 109 | { 110 | printHelpCmdFormat(HELP_READ_FORMAT); 111 | printHelp(HELP_READ_INTRO1); 112 | printHelp(HELP_READ_INTRO2); 113 | printHelp(HELP_READ_INTRO3); 114 | 115 | printHelp(HELP_READ_INT_VAL1); 116 | printHelp(HELP_READ_INT_VAL2); 117 | printHelp(HELP_READ_INT_VAL3); 118 | } 119 | else if(strcmp((*topicId), "output-voltage") == 0) 120 | { 121 | printHelpCmdFormat(HELP_SET_VOLTAGE_FORMAT); 122 | printHelp(HELP_SET_VOLTAGE_INTRO1); 123 | printHelp(HELP_SET_VOLTAGE_INTRO2); 124 | printHelp(HELP_SET_VOLTAGE_INTRO3); 125 | 126 | printHelp(HELP_SET_VOLTAGE_WARNING1); 127 | printHelp(HELP_SET_VOLTAGE_WARNING2); 128 | printHelp(HELP_SET_VOLTAGE_WARNING3); 129 | } 130 | else if(strcmp((*topicId), "reset") == 0) 131 | { 132 | printHelpCmdFormat(HELP_RESET_FORMAT); 133 | printHelp(HELP_RESET_INTRO1); 134 | printHelp(HELP_RESET_INTRO2); 135 | 136 | printHelp(HELP_RESET_POWER1); 137 | printHelp(HELP_RESET_POWER2); 138 | } 139 | else if(strcmp((*topicId), "exit") == 0) 140 | { 141 | printHelpCmdFormat(HELP_EXIT_FORMAT); 142 | printHelp(HELP_EXIT_INTRO); 143 | } 144 | else 145 | { 146 | // Help for the specified parameter is not available, show the general help screen. 147 | showGeneralHelp(); 148 | } 149 | } 150 | } -------------------------------------------------------------------------------- /terminal/src/docuproc.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------------- 2 | // I2C Test Terminal - Help / Documentation Processor. 3 | // 4 | // Copyright (c) 2021 Dilshan R Jayakody [jayakody2000lk@gmail.com]. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | //---------------------------------------------------------------------------------- 24 | 25 | #ifndef I2C_TERMINAL_DOCUMENTATION_PROC 26 | #define I2C_TERMINAL_DOCUMENTATION_PROC 27 | 28 | void showHelp(char **topicId); 29 | 30 | #endif /* I2C_TERMINAL_DOCUMENTATION_PROC */ -------------------------------------------------------------------------------- /terminal/src/main.c: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------------- 2 | // I2C Test Terminal - Core Functions and Main Entry Point. 3 | // 4 | // Copyright (c) 2021 Dilshan R Jayakody [jayakody2000lk@gmail.com]. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | //---------------------------------------------------------------------------------- 24 | 25 | #include "main.h" 26 | #include "strdef.h" 27 | #include "termutil.h" 28 | #include "cmdproc.h" 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | int main() 49 | { 50 | struct udev *udev; 51 | struct UsbComData comIntf; 52 | char *hidDevPath; 53 | unsigned char *cmdData; 54 | EXEC_STATUS status; 55 | pthread_t devThread; 56 | int termHandler; 57 | unsigned char currentVoltage, refreshVoltage; 58 | 59 | // Try to find the I2C terminal device on udev. If available get the device path. 60 | udev = udev_new(); 61 | status = getTerminalDevicePath(udev, &hidDevPath); 62 | udev_unref(udev); 63 | 64 | if(status == EXEC_FAIL) 65 | { 66 | // Unable to find the device or udev error. 67 | printErrorMsg(DEV_NOT_AVAILABLE); 68 | return 1; 69 | } 70 | 71 | // Open USB device for communication. 72 | termHandler = open(hidDevPath, (O_RDWR | O_NONBLOCK)); 73 | if(termHandler < 0) 74 | { 75 | printErrorMsg(DEV_NOT_OPEN); 76 | return 1; 77 | } 78 | 79 | // Display intro message(s). 80 | printf(MSG_INTRO_NAME); 81 | printf(MSG_INTRO_HELP); 82 | 83 | // Get current output voltage from the device. 84 | currentVoltage = 0; 85 | refreshVoltage = 0; 86 | if(getCurrentOutputVoltage(termHandler, ¤tVoltage) == EXEC_SUCCESS) 87 | { 88 | // Current output voltage received from the device. 89 | printf(MSG_OUTPUT_VOLTAGE, (currentVoltage == I2C_OUTPUT_5V) ? "5.0" : "3.3"); 90 | } 91 | else 92 | { 93 | // Output voltage probe request is fail. 94 | printErrorMsg(DEV_COM_OUTPUT_VOLTAGE_FAIL); 95 | return 1; 96 | } 97 | 98 | // Get commands from the user. 99 | while(getCommand(&cmdData) == CMD_STATUS_OK) 100 | { 101 | if(cmdData != NULL) 102 | { 103 | // Confirmation is required to change the I2C output voltage. 104 | if(cmdData[1] == USB_CMD_SET_VOLTAGE) 105 | { 106 | // Check specified voltage is same as the current voltage level. 107 | if(cmdData[2] != currentVoltage) 108 | { 109 | // Specified voltage level is different from current voltage level. 110 | if(isContinue(PROMPT_VOLTAGE_CHANGE) == EXEC_FAIL) 111 | { 112 | // Voltage change is canceled by the user. 113 | free(cmdData); 114 | cmdData = NULL; 115 | 116 | // No change required, skip USB data submission. 117 | continue; 118 | } 119 | } 120 | else 121 | { 122 | // Specified voltage level is equal to the current voltage level. 123 | printWarningMsg(CMD_VOLTAGE_SAME); 124 | 125 | // Release command buffer. 126 | free(cmdData); 127 | cmdData = NULL; 128 | 129 | // No change required, skip USB data submission. 130 | continue; 131 | } 132 | 133 | // After the command execute get the voltage level from the device. 134 | refreshVoltage = 1; 135 | } 136 | 137 | // Execute command available in the data buffer. 138 | comIntf.comData = cmdData; 139 | comIntf.deviceHandler = termHandler; 140 | pthread_create(&devThread, NULL, sendDataToDevice, (void*)&comIntf); 141 | 142 | // Wait to finish the USB command. 143 | pthread_join(devThread, NULL); 144 | 145 | // Release command buffer. 146 | free(cmdData); 147 | cmdData = NULL; 148 | 149 | if(refreshVoltage) 150 | { 151 | // Need to refresh the voltage level of the system. (associated with voltage-change and reset commands.) 152 | refreshVoltage = 0; 153 | 154 | if(getCurrentOutputVoltage(termHandler, ¤tVoltage) == EXEC_SUCCESS) 155 | { 156 | // Current output voltage received from the device. 157 | printf(MSG_OUTPUT_VOLTAGE, (currentVoltage == I2C_OUTPUT_5V) ? "5.0" : "3.3"); 158 | } 159 | else 160 | { 161 | // Output voltage probe request is fail. 162 | printErrorMsg(DEV_COM_OUTPUT_VOLTAGE_FAIL); 163 | return 1; 164 | } 165 | } 166 | } 167 | } 168 | 169 | // Release command buffer. 170 | if(cmdData != NULL) 171 | { 172 | free(cmdData); 173 | cmdData = NULL; 174 | } 175 | 176 | // Close USB device handler and terminate the application. 177 | close(termHandler); 178 | return 0; 179 | } 180 | 181 | EXEC_STATUS isContinue(const unsigned char *msg) 182 | { 183 | char getConfirmation; 184 | static struct termios conConfigOld, conConfigNew; 185 | 186 | // Print specified message on the terminal. 187 | printf("%s (Y/N) ? ", msg); 188 | 189 | // Cancel character printing on the termina. 190 | tcgetattr(0, &conConfigOld); 191 | conConfigNew = conConfigOld; 192 | conConfigNew.c_lflag &= ~ICANON; 193 | conConfigNew.c_lflag &= ~ECHO; 194 | tcsetattr(0, TCSANOW, &conConfigNew); 195 | 196 | // Loop until user specify the correct input. 197 | do 198 | { 199 | getConfirmation = getchar(); 200 | } 201 | while (!((getConfirmation == 'y') || (getConfirmation == 'Y') || (getConfirmation == 'n') || (getConfirmation == 'N'))); 202 | 203 | // Restore terminal settings (to print characters on screen). 204 | tcsetattr(0, TCSANOW, &conConfigOld); 205 | 206 | // Print user selection and move to next line. 207 | printf("%c\n", toupper(getConfirmation)); 208 | 209 | // Return success on "YES", otherwise return fail. 210 | return ((getConfirmation == 'y') || (getConfirmation == 'Y')) ? EXEC_SUCCESS : EXEC_FAIL; 211 | } 212 | 213 | EXEC_STATUS getCurrentOutputVoltage(int deviceHandler, unsigned char *voltage) 214 | { 215 | unsigned char *reqData, *respData; 216 | struct timespec req, rem; 217 | int status; 218 | unsigned char result = EXEC_FAIL; 219 | 220 | // Create request buffer and send it to the device. 221 | reqData = createUSBBuffer(USB_CMD_GET_VOLTAGE, 0); 222 | respData = NULL; 223 | 224 | status = ioctl(deviceHandler, HIDIOCSFEATURE(USB_SET_COMMAND_BUFFER_SIZE), reqData); 225 | if(status >= 0) 226 | { 227 | // IOCTL is successful, creating data buffer to capture the output from the device. 228 | respData = (unsigned char*)calloc(USB_GET_DATA_BUFFER_SIZE, 1); 229 | while(ioctl(deviceHandler, HIDIOCGFEATURE(USB_GET_DATA_BUFFER_SIZE), respData) >= 0) 230 | { 231 | if((respData[1] == SYS_SIGNATURE) && (respData[2] == reqData[1]) && (respData[3] != RET_PENDING)) 232 | { 233 | // Device respond with data / status. 234 | *voltage = respData[4]; 235 | result = EXEC_SUCCESS; 236 | break; 237 | } 238 | 239 | // Wait thread for 250ms to get the next feature report. 240 | req.tv_sec = 0; 241 | req.tv_nsec = 250 * 1000000; 242 | nanosleep(&req , &rem); 243 | 244 | memset(respData, 0, USB_GET_DATA_BUFFER_SIZE); 245 | } 246 | } 247 | 248 | // Release all allocated data buffers. 249 | free(reqData); 250 | reqData = NULL; 251 | 252 | if(respData != NULL) 253 | { 254 | free(respData); 255 | respData = NULL; 256 | } 257 | 258 | return result; 259 | } 260 | 261 | void *sendDataToDevice(void *dataPtr) 262 | { 263 | struct UsbComData *comData = (struct UsbComData *)dataPtr; 264 | struct timespec req, rem; 265 | int status; 266 | unsigned char readBuffer[USB_GET_DATA_BUFFER_SIZE]; 267 | 268 | // Send specified USB data buffer to the device. 269 | status = ioctl(comData->deviceHandler, HIDIOCSFEATURE(USB_SET_COMMAND_BUFFER_SIZE), comData->comData); 270 | if(status < 0) 271 | { 272 | // Communication failure has occur while setting up the feature report. 273 | printErrorMsg(DEV_COM_FAIL); 274 | } 275 | else 276 | { 277 | // IOCTL is successful, waiting for response from the device. 278 | memset(readBuffer, 0, USB_GET_DATA_BUFFER_SIZE); 279 | while(ioctl(comData->deviceHandler, HIDIOCGFEATURE(USB_GET_DATA_BUFFER_SIZE), readBuffer) >= 0) 280 | { 281 | if((readBuffer[1] == SYS_SIGNATURE) && (readBuffer[2] == comData->comData[1]) && (readBuffer[3] != RET_PENDING)) 282 | { 283 | // Device respond with data / status. 284 | break; 285 | } 286 | 287 | // Wait thread for 250ms to get the next feature report. 288 | req.tv_sec = 0; 289 | req.tv_nsec = 250 * 1000000; 290 | nanosleep(&req , &rem); 291 | 292 | memset(readBuffer, 0, USB_GET_DATA_BUFFER_SIZE); 293 | } 294 | 295 | // print received data and status on terminal. 296 | printDeviceStatusMsg(readBuffer[3]); 297 | 298 | // On READ command show received data. 299 | if(readBuffer[2] == USB_CMD_I2C_READ) 300 | { 301 | printData(readBuffer[4]); 302 | } 303 | } 304 | } 305 | 306 | EXEC_STATUS getTerminalDevicePath(struct udev *udev, char **hidRawPath) 307 | { 308 | EXEC_STATUS returnVal; 309 | struct udev_enumerate *devEnum; 310 | struct udev_list_entry *devices, *devEntry; 311 | struct udev_device *rawDev, *hidDev, *usbDev; 312 | const char *sysfsPath, *devPath, *devVID, *devPID; 313 | int parseStatus; 314 | unsigned short vid, pid; 315 | 316 | *hidRawPath = NULL; 317 | returnVal = EXEC_FAIL; 318 | 319 | // Perform device scan on HID-RAW device class. 320 | devEnum = udev_enumerate_new(udev); 321 | udev_enumerate_add_match_subsystem(devEnum, "hidraw"); 322 | udev_enumerate_scan_devices(devEnum); 323 | 324 | // Get the list of HID devices attached to the system. 325 | devices = udev_enumerate_get_list_entry(devEnum); 326 | 327 | // Check for the VID and PID to identify the I2C terminal device entry. 328 | udev_list_entry_foreach(devEntry, devices) 329 | { 330 | devVID = NULL; 331 | devPID = NULL; 332 | vid = 0; 333 | pid = 0; 334 | 335 | // Get devices HID RAW udev node. 336 | sysfsPath = udev_list_entry_get_name(devEntry); 337 | rawDev = udev_device_new_from_syspath(udev, sysfsPath); 338 | 339 | // Get devices HID udev node. 340 | devPath = udev_device_get_devnode(rawDev); 341 | hidDev = udev_device_get_parent_with_subsystem_devtype(rawDev, "hid", NULL); 342 | 343 | if(hidDev) 344 | { 345 | // Get USB device class to extract VID and PID values. 346 | usbDev = udev_device_get_parent_with_subsystem_devtype(rawDev, "usb", "usb_device"); 347 | if(usbDev) 348 | { 349 | devVID = udev_device_get_sysattr_value(usbDev, "idVendor"); 350 | devPID = udev_device_get_sysattr_value(usbDev, "idProduct"); 351 | 352 | // Get vendor ID of the selected device. 353 | if((devVID) && (strlen(devVID) > 0)) 354 | { 355 | vid = strtol(devVID, NULL, 16); 356 | } 357 | 358 | // Get product ID of the selected device. 359 | if((devPID) && (strlen(devPID) > 0)) 360 | { 361 | pid = strtol(devPID, NULL, 16); 362 | } 363 | 364 | // Check for valid VID and PID. 365 | if((vid == I2C_TERMINAL_DEV_VID) && (pid == I2C_TERMINAL_DEV_PID)) 366 | { 367 | // Copy HID-RAW device path into specified variable. 368 | *hidRawPath = (char*) malloc(strlen(devPath) + 1); 369 | strcpy(*hidRawPath, devPath); 370 | 371 | returnVal = EXEC_SUCCESS; 372 | } 373 | 374 | free((char*) devVID); 375 | free((char*) devPID); 376 | 377 | udev_device_unref(usbDev); 378 | } 379 | } 380 | 381 | free((char*) devPath); 382 | } 383 | 384 | // Cleanup allocated data structures. 385 | udev_enumerate_unref(devEnum); 386 | 387 | return returnVal; 388 | } -------------------------------------------------------------------------------- /terminal/src/main.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------------- 2 | // I2C Test Terminal - Core Functions and Main Entry Point. 3 | // 4 | // Copyright (c) 2021 Dilshan R Jayakody [jayakody2000lk@gmail.com]. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | //---------------------------------------------------------------------------------- 24 | 25 | #ifndef I2C_TERMINAL_MAIN 26 | #define I2C_TERMINAL_MAIN 27 | 28 | #include 29 | 30 | #include "common.h" 31 | 32 | #define I2C_TERMINAL_DEV_VID 0x16C0 33 | #define I2C_TERMINAL_DEV_PID 0x1231 34 | 35 | void *sendDataToDevice(void *dataPtr); 36 | EXEC_STATUS getTerminalDevicePath(struct udev *udev, char **hidRawPath); 37 | EXEC_STATUS getCurrentOutputVoltage(int deviceHandler, unsigned char *voltage); 38 | EXEC_STATUS isContinue(const unsigned char *msg); 39 | 40 | #endif /* I2C_TERMINAL_MAIN */ -------------------------------------------------------------------------------- /terminal/src/strdef.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------------- 2 | // I2C Test Terminal - Generic String Table. 3 | // 4 | // Copyright (c) 2021 Dilshan R Jayakody [jayakody2000lk@gmail.com]. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | //---------------------------------------------------------------------------------- 24 | 25 | #ifndef I2C_TERMINAL_STR_DEF 26 | #define I2C_TERMINAL_STR_DEF 27 | 28 | #define DEV_NOT_AVAILABLE "I2C Terminal device is not connected to the system or not functioning properly." 29 | #define DEV_NOT_OPEN "Unable to open the USB device." 30 | 31 | #define MSG_INTRO_NAME "I2C Terminal - Copyright (c) 2021 Dilshan R Jayakody. (jayakody2000lk@gmail.com)\n" 32 | #define MSG_INTRO_HELP "Type \"\033[1m\033[37mhelp\033[0m\" to list down the available commands. Enter \"\033[1m\033[37mhelp [COMMAND]\033[0m\" to get the information about the specific command.\n" 33 | #define MSG_OUTPUT_VOLTAGE "Current I2C output voltage: \033[1m\033[37m%sV\033[0m\n" 34 | 35 | #define CMD_MSG_UNKNOWN "Unknown command." 36 | #define CMD_MSG_PARAMETER_MISSING "Required parameter(s) are missing." 37 | #define CMD_MSG_OUTOF_RANGE "Specified parameter is out of range." 38 | #define CMD_MSG_SPEED_UNSUPPORT "Unsupported I2C speed, only 100kHz, 250kHz and 400kHz are supported by the device." 39 | #define CMD_PARAM_IGNORE "Specified parameters are ignored by the command." 40 | #define CMD_PARAM_READ_UNSUPPORTED "Unsupported read flag, only \033[1m\033[37mack\033[0m, \033[1m\033[37mnack\033[0m, \033[1m\033[37m1\033[0m and \033[1m\033[37m0\033[0m are allowd as parameters." 41 | #define CMD_PARAM_INVALID_VOLTAGE "Invalid voltage level, only 3.3V or 5V output is available with the device." 42 | #define CMD_VOLTAGE_SAME "Current output voltage is same as the specified voltage." 43 | 44 | #define PROMPT_VOLTAGE_CHANGE "Selected voltage level is different from the current output voltage, continue the voltage change" 45 | 46 | #define DEV_COM_FAIL "Communication failure has occur while writing data to the device." 47 | #define DEV_COM_TIMEOUT "I2C timeout occur, slave device is not responding." 48 | #define DEV_COM_UNKNOWN "Unknown I2C error." 49 | #define DEV_COM_OUTPUT_VOLTAGE_FAIL "Unable to get I2C output voltage from the device." 50 | 51 | #define DEV_COM_START_TX "A START condition has been transmitted." 52 | #define DEV_COM_REPEAT_START "A repeated START condition has been transmitted." 53 | #define DEV_COM_SLAVE_W "Slave address with WRITE flag has been transmitted, ACK has been received." 54 | #define DEV_COM_SLAVE_W_NACK "Slave address with WRITE flag has been transmitted, NOT ACK has been received." 55 | #define DEV_COM_NOT_ACK "Slave address with READ flag has been transmitted, ACK has been received." 56 | #define DEV_COM_DATA_TX "Data byte has been transmitted, ACK has been received." 57 | #define DEV_COM_DATA_TX_NACK "Data byte has been transmitted, NOT ACK has been received." 58 | #define DEV_COM_ARIB_LOST "Arbitration lost in Slave address (with WRITE flag) or data bytes." 59 | #define DEV_COM_REPEATE_WAIT "Slave address with READ flag has been transmitted, NOT ACK has been received" 60 | #define DEV_COM_DATA_TX_ACK "Data byte has been received, ACK has been returned." 61 | #define DEV_COM_DATA_RX_NACK "Data byte has been received, NOT ACK has been returned." 62 | 63 | #endif /* I2C_TERMINAL_STR_DEF */ -------------------------------------------------------------------------------- /terminal/src/strdoc.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------------- 2 | // I2C Test Terminal - String Table for Documentation / Help. 3 | // 4 | // Copyright (c) 2021 Dilshan R Jayakody [jayakody2000lk@gmail.com]. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | //---------------------------------------------------------------------------------- 24 | 25 | #ifndef I2C_TERMINAL_STR_HELP_DEF 26 | #define I2C_TERMINAL_STR_HELP_DEF 27 | 28 | // General help. 29 | 30 | #define HELP_GEN_ABOUT "Following commands are available for the I2C test terminal:" 31 | #define HELP_GEN_CMD_HELP "- help" 32 | #define HELP_GEN_CMD_INIT "- init" 33 | #define HELP_GEN_CMD_START "- start" 34 | #define HELP_GEN_CMD_STOP "- stop" 35 | #define HELP_GEN_CMD_WRITE "- write" 36 | #define HELP_GEN_CMD_WRITE_ADDR "- write-address" 37 | #define HELP_GEN_CMD_READ "- read" 38 | #define HELP_GEN_CMD_OUT_VOLTAGE "- output-voltage" 39 | #define HELP_GEN_CMD_RESET "- reset" 40 | #define HELP_GEN_CMD_EXIT "- exit" 41 | 42 | #define HELP_USE_HELP1 "\nTo get details, enter the help command with one of the above commands." 43 | #define HELP_USE_HELP2 "For example:" 44 | #define HELP_USE_HELP3 "\n\033[1m\033[37m help reset\033[0m" 45 | 46 | #define HELP_AUTO_COMPLETE1 "\nI2C test terminal has an auto-complete command prompt. To use this" 47 | #define HELP_AUTO_COMPLETE2 "option, press the TAB key twice on the command prompt." 48 | 49 | #define HELP_GITHUB_REF1 "\nTo get the latest version of this application, device firmware, or the" 50 | #define HELP_GITHUB_REF2 "documentation, visit https://github.com/dilshan/i2c-test-terminal.\n" 51 | 52 | // Help for INIT command. 53 | 54 | #define HELP_INIT_FORMAT "Format: init [SPEED]" 55 | #define HELP_INIT_INTRO1 "\nInitialize the I2C bus with the given speed. For the \033[1m\033[37m[SPEED]\033[0m specify one" 56 | #define HELP_INIT_INTRO2 "of the following speed configurations:" 57 | 58 | #define HELP_INIT_SPEED_100 "\n100: 100kHz" 59 | #define HELP_INIT_SPEED_250 "250: 250kHz" 60 | #define HELP_INIT_SPEED_400 "400: 400kHz" 61 | 62 | #define HELP_INIT_WARNING1 "\nThis command must issue before continue with any I2C request." 63 | #define HELP_INIT_WARNING2 "\n" 64 | 65 | // Help for START command. 66 | 67 | #define HELP_START_FORMAT "Format: start" 68 | #define HELP_START_INTRO1 "\nIssue this command to raise the I2C START condition. Each I2C" 69 | #define HELP_START_INTRO2 "session initiated by the I2C test terminal must with a START" 70 | #define HELP_START_INTRO3 "condition.\n" 71 | 72 | // Help for STOP command. 73 | 74 | #define HELP_STOP_FORMAT "Format: stop" 75 | #define HELP_STOP_INTRO1 "\nIssue this command to raise the I2C STOP condition. A Stop condition" 76 | #define HELP_STOP_INTRO2 "always denotes the END of a transmission.\n" 77 | 78 | // Help for WRITE command. 79 | 80 | #define HELP_WRITE_FORMAT "Format: write [VALUE]" 81 | #define HELP_WRITE_INTRO1 "\nWrite/send specified \033[1m\033[37m[VALUE]\033[0m into the I2C bus. In this command, \033[1m\033[37m[VALUE]\033[0m" 82 | #define HELP_WRITE_INTRO2 "is an 8-bit (base 10) integer or hexadecimal value. All hexadecimal values" 83 | #define HELP_WRITE_INTRO3 "must begin with the \"\033[1m\033[37m0x\033[0m\" prefix.\n" 84 | 85 | // Help for WRITE-ADDRESS command. 86 | 87 | #define HELP_WRITE_ADDR_FORMAT "Format: write-address [VALUE]" 88 | #define HELP_WRITE_ADDR_INTRO1 "\nWrite slave address into the I2C bus. In this command, \033[1m\033[37m[VALUE]\033[0m is a" 89 | #define HELP_WRITE_ADDR_INTRO2 "combination of a 7-bit slave address with the read/write flag bit. The" 90 | #define HELP_WRITE_ADDR_INTRO3 "\033[1m\033[37m[VALUE]\033[0m parameter accepts (base 10) integer or hexadecimal value. All" 91 | #define HELP_WRITE_ADDR_INTRO4 "hexadecimal values must begin with the \"\033[1m\033[37m0x\033[0m\" prefix.\n" 92 | 93 | // Help for READ command. 94 | 95 | #define HELP_READ_FORMAT "Format: read {FLAG}" 96 | #define HELP_READ_INTRO1 "\nRead data byte available in the I2C bus. In this command, \033[1m\033[37m{FLAG}\033[0m is an" 97 | #define HELP_READ_INTRO2 "optional value to specify the ACK or NACK condition. If \033[1m\033[37m{FLAG}\033[0m is not" 98 | #define HELP_READ_INTRO3 "specified, the I2C terminal issue NACK to the I2C slave device." 99 | 100 | #define HELP_READ_INT_VAL1 "\nThe \033[1m\033[37m{FLAG}\033[0m parameter also accepts integer values as ACK or NACK. For" 101 | #define HELP_READ_INT_VAL2 "the ACK, specify 1 for the \033[1m\033[37m{FLAG}\033[0m parameter, and use 0 for the NACK" 102 | #define HELP_READ_INT_VAL3 "condition.\n" 103 | 104 | // Help for SET-VOLTAGE command. 105 | 106 | #define HELP_SET_VOLTAGE_FORMAT "Format: output-voltage [VOLTAGE]" 107 | #define HELP_SET_VOLTAGE_INTRO1 "\nIssue this command to set the output voltage of the I2C test terminal. For" 108 | #define HELP_SET_VOLTAGE_INTRO2 "this command, accepted values for \033[1m\033[37m[VOLTAGE]\033[0m parameter are 3.3, 3.3V or" 109 | #define HELP_SET_VOLTAGE_INTRO3 "5, 5.0, 5V, 5.0V." 110 | 111 | #define HELP_SET_VOLTAGE_WARNING1 "\nIt is recommended to call this function and set the output voltage at the" 112 | #define HELP_SET_VOLTAGE_WARNING2 "beginning of the I2C emulation. This command is not advisable to use in" 113 | #define HELP_SET_VOLTAGE_WARNING3 "the middle of the I2C session(s).\n" 114 | 115 | // Help for RESET command. 116 | 117 | #define HELP_RESET_FORMAT "Format: reset" 118 | #define HELP_RESET_INTRO1 "\nThis command resets both power and internal data buffers of the I2C test" 119 | #define HELP_RESET_INTRO2 "terminal." 120 | 121 | #define HELP_RESET_POWER1 "\nDuring the power reset I2C terminal does not reset the voltage level of" 122 | #define HELP_RESET_POWER2 "the output terminal.\n" 123 | 124 | // Help for EXIT command. 125 | 126 | #define HELP_EXIT_FORMAT "Format: exit" 127 | #define HELP_EXIT_INTRO "\nIssue this command to close the I2C test terminal session.\n" 128 | 129 | #endif /* I2C_TERMINAL_STR_HELP_DEF */ 130 | -------------------------------------------------------------------------------- /terminal/src/termutil.c: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------------- 2 | // I2C Test Terminal - Display and Terminal Related Helper Functions. 3 | // 4 | // Copyright (c) 2021 Dilshan R Jayakody [jayakody2000lk@gmail.com]. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | //---------------------------------------------------------------------------------- 24 | 25 | #include "termutil.h" 26 | #include "common.h" 27 | #include "strdef.h" 28 | 29 | #include 30 | 31 | void printDeviceStatusMsg(unsigned char errorCode) 32 | { 33 | switch(errorCode) 34 | { 35 | // Terminal base errors. 36 | case USB_CMD_NONE: 37 | // No Error. 38 | break; 39 | case RET_TIMEOUT_FAIL: 40 | printErrorMsg(DEV_COM_TIMEOUT); 41 | break; 42 | case RET_UNKNOWN: 43 | printErrorMsg(DEV_COM_UNKNOWN); 44 | break; 45 | // I2C specific status codes. 46 | case 0x08: 47 | printStatus(DEV_COM_START_TX); 48 | break; 49 | case 0x10: 50 | printStatus(DEV_COM_REPEAT_START); 51 | break; 52 | case 0x18: 53 | printStatus(DEV_COM_SLAVE_W); 54 | break; 55 | case 0x20: 56 | printStatus(DEV_COM_SLAVE_W_NACK); 57 | break; 58 | case 0x28: 59 | printStatus(DEV_COM_DATA_TX); 60 | break; 61 | case 0x30: 62 | printStatus(DEV_COM_DATA_TX_NACK); 63 | break; 64 | case 0x38: 65 | printStatus(DEV_COM_ARIB_LOST); 66 | break; 67 | case 0x40: 68 | printStatus(DEV_COM_NOT_ACK); 69 | break; 70 | case 0x48: 71 | printStatus(DEV_COM_REPEATE_WAIT); 72 | break; 73 | case 0x50: 74 | printStatus(DEV_COM_DATA_TX_ACK); 75 | break; 76 | case 0x58: 77 | printStatus(DEV_COM_DATA_RX_NACK); 78 | break; 79 | // Unknown error code. 80 | default: 81 | printf(ERROR_UNKNOWN_FORMATTER, errorCode, DEV_COM_UNKNOWN); 82 | } 83 | } -------------------------------------------------------------------------------- /terminal/src/termutil.h: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------------- 2 | // I2C Test Terminal - Display and Terminal Related Helper Functions. 3 | // 4 | // Copyright (c) 2021 Dilshan R Jayakody [jayakody2000lk@gmail.com]. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | //---------------------------------------------------------------------------------- 24 | 25 | #ifndef I2C_TERMINAL_UTILITIES 26 | #define I2C_TERMINAL_UTILITIES 27 | 28 | #define ERROR_TEXT_FORMATTER "\x1b[31m%s\x1b[0m\n" 29 | #define ERROR_TEXT_FORMATTER_EX "\x1b[31m%s: %s\x1b[0m\n" 30 | #define ERROR_UNKNOWN_FORMATTER "\x1b[31m0x%x: %s\x1b[0m\n" 31 | #define WARNING_TEXT_FORMATTER "%s\n" 32 | #define STATUS_TEXT_FORMATTER "\x1b[33m%s\x1b[0m\n" 33 | #define HELP_TEXT_FORMATTER "%s\n" 34 | #define HELP_CMDFORMAT_FORMATTER "\x1B[33m%s\x1B[0m\n" 35 | 36 | void printDeviceStatusMsg(unsigned char errorCode); 37 | 38 | #define printErrorMsg(x) printf(ERROR_TEXT_FORMATTER, x) 39 | #define printCommandError(m, p) printf(ERROR_TEXT_FORMATTER_EX, p, m) 40 | #define printWarningMsg(x) printf(WARNING_TEXT_FORMATTER, x) 41 | #define printData(x) printf("Data: 0x%x\n", x) 42 | #define printStatus(x) printf(STATUS_TEXT_FORMATTER, x) 43 | #define printHelp(x) printf(HELP_TEXT_FORMATTER, x) 44 | #define printHelpCmdFormat(x) printf(HELP_CMDFORMAT_FORMATTER, x) 45 | 46 | #endif /* I2C_TERMINAL_UTILITIES */ --------------------------------------------------------------------------------