├── License.txt ├── Makefile ├── Makefile.hid ├── README ├── apps ├── Makefile ├── rgb.c ├── segled.c ├── simple_blinky.c └── simple_blinky.hex ├── bbusb.h ├── bbusb.inc ├── bbusb_packet.c ├── bbusb_protocol.c ├── bbusb_protocol_hid.c ├── bbusb_receive.S ├── bbusb_transmit.S ├── boot430.c ├── boot430.hex ├── commandline ├── Makefile ├── boot430load.exe ├── hidsdi.h ├── main.c ├── usb-libusb.c ├── usb-windows.c ├── usbcalls.c └── usbcalls.h ├── hid430.c └── hid430.hex /License.txt: -------------------------------------------------------------------------------- 1 | 2 | January 2013 3 | 4 | the boot430 project package includes works from 5 | 6 | . Matthias Koch, Mecrimus-B, provides orginal assembler usb implementation 7 | . Kevin Timmerman, oPossum, provides TI ccs v4 translation on usb implementation 8 | . Chris Chung, simpleavr, www.simpleavr.com, provides mspgcc translation 9 | and bootloader application logic 10 | . Christian Starkjohann, OBJECTIVE DEVELOPMENT Software GmbH, www.obdev.at 11 | reference hid bootloader project, commandline code framework used in this project 12 | 13 | software is released w/ the same licensing as V-USB licensce, which is includes as follows 14 | 15 | OBJECTIVE DEVELOPMENT GmbH's V-USB driver software is distributed under the 16 | terms and conditions of the GNU GPL version 2 or the GNU GPL version 3. It is 17 | your choice whether you apply the terms of version 2 or version 3. The full 18 | text of GPLv2 is included below. In addition to the requirements in the GPL, 19 | we STRONGLY ENCOURAGE you to do the following: 20 | 21 | (1) Publish your entire project on a web site and drop us a note with the URL. 22 | Use the form at http://www.obdev.at/vusb/feedback.html for your submission. 23 | 24 | (2) Adhere to minimum publication standards. Please include AT LEAST: 25 | - a circuit diagram in PDF, PNG or GIF format 26 | - full source code for the host software 27 | - a Readme.txt file in ASCII format which describes the purpose of the 28 | project and what can be found in which directories and which files 29 | - a reference to http://www.obdev.at/vusb/ 30 | 31 | (3) If you improve the driver firmware itself, please give us a free license 32 | to your modifications for our commercial license offerings. 33 | 34 | 35 | 36 | GNU GENERAL PUBLIC LICENSE 37 | Version 2, June 1991 38 | 39 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 40 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 41 | Everyone is permitted to copy and distribute verbatim copies 42 | of this license document, but changing it is not allowed. 43 | 44 | Preamble 45 | 46 | The licenses for most software are designed to take away your 47 | freedom to share and change it. By contrast, the GNU General Public 48 | License is intended to guarantee your freedom to share and change free 49 | software--to make sure the software is free for all its users. This 50 | General Public License applies to most of the Free Software 51 | Foundation's software and to any other program whose authors commit to 52 | using it. (Some other Free Software Foundation software is covered by 53 | the GNU Library General Public License instead.) You can apply it to 54 | your programs, too. 55 | 56 | When we speak of free software, we are referring to freedom, not 57 | price. Our General Public Licenses are designed to make sure that you 58 | have the freedom to distribute copies of free software (and charge for 59 | this service if you wish), that you receive source code or can get it 60 | if you want it, that you can change the software or use pieces of it 61 | in new free programs; and that you know you can do these things. 62 | 63 | To protect your rights, we need to make restrictions that forbid 64 | anyone to deny you these rights or to ask you to surrender the rights. 65 | These restrictions translate to certain responsibilities for you if you 66 | distribute copies of the software, or if you modify it. 67 | 68 | For example, if you distribute copies of such a program, whether 69 | gratis or for a fee, you must give the recipients all the rights that 70 | you have. You must make sure that they, too, receive or can get the 71 | source code. And you must show them these terms so they know their 72 | rights. 73 | 74 | We protect your rights with two steps: (1) copyright the software, and 75 | (2) offer you this license which gives you legal permission to copy, 76 | distribute and/or modify the software. 77 | 78 | Also, for each author's protection and ours, we want to make certain 79 | that everyone understands that there is no warranty for this free 80 | software. If the software is modified by someone else and passed on, we 81 | want its recipients to know that what they have is not the original, so 82 | that any problems introduced by others will not reflect on the original 83 | authors' reputations. 84 | 85 | Finally, any free program is threatened constantly by software 86 | patents. We wish to avoid the danger that redistributors of a free 87 | program will individually obtain patent licenses, in effect making the 88 | program proprietary. To prevent this, we have made it clear that any 89 | patent must be licensed for everyone's free use or not licensed at all. 90 | 91 | The precise terms and conditions for copying, distribution and 92 | modification follow. 93 | 94 | GNU GENERAL PUBLIC LICENSE 95 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 96 | 97 | 0. This License applies to any program or other work which contains 98 | a notice placed by the copyright holder saying it may be distributed 99 | under the terms of this General Public License. The "Program", below, 100 | refers to any such program or work, and a "work based on the Program" 101 | means either the Program or any derivative work under copyright law: 102 | that is to say, a work containing the Program or a portion of it, 103 | either verbatim or with modifications and/or translated into another 104 | language. (Hereinafter, translation is included without limitation in 105 | the term "modification".) Each licensee is addressed as "you". 106 | 107 | Activities other than copying, distribution and modification are not 108 | covered by this License; they are outside its scope. The act of 109 | running the Program is not restricted, and the output from the Program 110 | is covered only if its contents constitute a work based on the 111 | Program (independent of having been made by running the Program). 112 | Whether that is true depends on what the Program does. 113 | 114 | 1. You may copy and distribute verbatim copies of the Program's 115 | source code as you receive it, in any medium, provided that you 116 | conspicuously and appropriately publish on each copy an appropriate 117 | copyright notice and disclaimer of warranty; keep intact all the 118 | notices that refer to this License and to the absence of any warranty; 119 | and give any other recipients of the Program a copy of this License 120 | along with the Program. 121 | 122 | You may charge a fee for the physical act of transferring a copy, and 123 | you may at your option offer warranty protection in exchange for a fee. 124 | 125 | 2. You may modify your copy or copies of the Program or any portion 126 | of it, thus forming a work based on the Program, and copy and 127 | distribute such modifications or work under the terms of Section 1 128 | above, provided that you also meet all of these conditions: 129 | 130 | a) You must cause the modified files to carry prominent notices 131 | stating that you changed the files and the date of any change. 132 | 133 | b) You must cause any work that you distribute or publish, that in 134 | whole or in part contains or is derived from the Program or any 135 | part thereof, to be licensed as a whole at no charge to all third 136 | parties under the terms of this License. 137 | 138 | c) If the modified program normally reads commands interactively 139 | when run, you must cause it, when started running for such 140 | interactive use in the most ordinary way, to print or display an 141 | announcement including an appropriate copyright notice and a 142 | notice that there is no warranty (or else, saying that you provide 143 | a warranty) and that users may redistribute the program under 144 | these conditions, and telling the user how to view a copy of this 145 | License. (Exception: if the Program itself is interactive but 146 | does not normally print such an announcement, your work based on 147 | the Program is not required to print an announcement.) 148 | 149 | These requirements apply to the modified work as a whole. If 150 | identifiable sections of that work are not derived from the Program, 151 | and can be reasonably considered independent and separate works in 152 | themselves, then this License, and its terms, do not apply to those 153 | sections when you distribute them as separate works. But when you 154 | distribute the same sections as part of a whole which is a work based 155 | on the Program, the distribution of the whole must be on the terms of 156 | this License, whose permissions for other licensees extend to the 157 | entire whole, and thus to each and every part regardless of who wrote it. 158 | 159 | Thus, it is not the intent of this section to claim rights or contest 160 | your rights to work written entirely by you; rather, the intent is to 161 | exercise the right to control the distribution of derivative or 162 | collective works based on the Program. 163 | 164 | In addition, mere aggregation of another work not based on the Program 165 | with the Program (or with a work based on the Program) on a volume of 166 | a storage or distribution medium does not bring the other work under 167 | the scope of this License. 168 | 169 | 3. You may copy and distribute the Program (or a work based on it, 170 | under Section 2) in object code or executable form under the terms of 171 | Sections 1 and 2 above provided that you also do one of the following: 172 | 173 | a) Accompany it with the complete corresponding machine-readable 174 | source code, which must be distributed under the terms of Sections 175 | 1 and 2 above on a medium customarily used for software interchange; or, 176 | 177 | b) Accompany it with a written offer, valid for at least three 178 | years, to give any third party, for a charge no more than your 179 | cost of physically performing source distribution, a complete 180 | machine-readable copy of the corresponding source code, to be 181 | distributed under the terms of Sections 1 and 2 above on a medium 182 | customarily used for software interchange; or, 183 | 184 | c) Accompany it with the information you received as to the offer 185 | to distribute corresponding source code. (This alternative is 186 | allowed only for noncommercial distribution and only if you 187 | received the program in object code or executable form with such 188 | an offer, in accord with Subsection b above.) 189 | 190 | The source code for a work means the preferred form of the work for 191 | making modifications to it. For an executable work, complete source 192 | code means all the source code for all modules it contains, plus any 193 | associated interface definition files, plus the scripts used to 194 | control compilation and installation of the executable. However, as a 195 | special exception, the source code distributed need not include 196 | anything that is normally distributed (in either source or binary 197 | form) with the major components (compiler, kernel, and so on) of the 198 | operating system on which the executable runs, unless that component 199 | itself accompanies the executable. 200 | 201 | If distribution of executable or object code is made by offering 202 | access to copy from a designated place, then offering equivalent 203 | access to copy the source code from the same place counts as 204 | distribution of the source code, even though third parties are not 205 | compelled to copy the source along with the object code. 206 | 207 | 4. You may not copy, modify, sublicense, or distribute the Program 208 | except as expressly provided under this License. Any attempt 209 | otherwise to copy, modify, sublicense or distribute the Program is 210 | void, and will automatically terminate your rights under this License. 211 | However, parties who have received copies, or rights, from you under 212 | this License will not have their licenses terminated so long as such 213 | parties remain in full compliance. 214 | 215 | 5. You are not required to accept this License, since you have not 216 | signed it. However, nothing else grants you permission to modify or 217 | distribute the Program or its derivative works. These actions are 218 | prohibited by law if you do not accept this License. Therefore, by 219 | modifying or distributing the Program (or any work based on the 220 | Program), you indicate your acceptance of this License to do so, and 221 | all its terms and conditions for copying, distributing or modifying 222 | the Program or works based on it. 223 | 224 | 6. Each time you redistribute the Program (or any work based on the 225 | Program), the recipient automatically receives a license from the 226 | original licensor to copy, distribute or modify the Program subject to 227 | these terms and conditions. You may not impose any further 228 | restrictions on the recipients' exercise of the rights granted herein. 229 | You are not responsible for enforcing compliance by third parties to 230 | this License. 231 | 232 | 7. If, as a consequence of a court judgment or allegation of patent 233 | infringement or for any other reason (not limited to patent issues), 234 | conditions are imposed on you (whether by court order, agreement or 235 | otherwise) that contradict the conditions of this License, they do not 236 | excuse you from the conditions of this License. If you cannot 237 | distribute so as to satisfy simultaneously your obligations under this 238 | License and any other pertinent obligations, then as a consequence you 239 | may not distribute the Program at all. For example, if a patent 240 | license would not permit royalty-free redistribution of the Program by 241 | all those who receive copies directly or indirectly through you, then 242 | the only way you could satisfy both it and this License would be to 243 | refrain entirely from distribution of the Program. 244 | 245 | If any portion of this section is held invalid or unenforceable under 246 | any particular circumstance, the balance of the section is intended to 247 | apply and the section as a whole is intended to apply in other 248 | circumstances. 249 | 250 | It is not the purpose of this section to induce you to infringe any 251 | patents or other property right claims or to contest validity of any 252 | such claims; this section has the sole purpose of protecting the 253 | integrity of the free software distribution system, which is 254 | implemented by public license practices. Many people have made 255 | generous contributions to the wide range of software distributed 256 | through that system in reliance on consistent application of that 257 | system; it is up to the author/donor to decide if he or she is willing 258 | to distribute software through any other system and a licensee cannot 259 | impose that choice. 260 | 261 | This section is intended to make thoroughly clear what is believed to 262 | be a consequence of the rest of this License. 263 | 264 | 8. If the distribution and/or use of the Program is restricted in 265 | certain countries either by patents or by copyrighted interfaces, the 266 | original copyright holder who places the Program under this License 267 | may add an explicit geographical distribution limitation excluding 268 | those countries, so that distribution is permitted only in or among 269 | countries not thus excluded. In such case, this License incorporates 270 | the limitation as if written in the body of this License. 271 | 272 | 9. The Free Software Foundation may publish revised and/or new versions 273 | of the General Public License from time to time. Such new versions will 274 | be similar in spirit to the present version, but may differ in detail to 275 | address new problems or concerns. 276 | 277 | Each version is given a distinguishing version number. If the Program 278 | specifies a version number of this License which applies to it and "any 279 | later version", you have the option of following the terms and conditions 280 | either of that version or of any later version published by the Free 281 | Software Foundation. If the Program does not specify a version number of 282 | this License, you may choose any version ever published by the Free Software 283 | Foundation. 284 | 285 | 10. If you wish to incorporate parts of the Program into other free 286 | programs whose distribution conditions are different, write to the author 287 | to ask for permission. For software which is copyrighted by the Free 288 | Software Foundation, write to the Free Software Foundation; we sometimes 289 | make exceptions for this. Our decision will be guided by the two goals 290 | of preserving the free status of all derivatives of our free software and 291 | of promoting the sharing and reuse of software generally. 292 | 293 | NO WARRANTY 294 | 295 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 296 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 297 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 298 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 299 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 300 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 301 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 302 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 303 | REPAIR OR CORRECTION. 304 | 305 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 306 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 307 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 308 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 309 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 310 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 311 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 312 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 313 | POSSIBILITY OF SUCH DAMAGES. 314 | 315 | END OF TERMS AND CONDITIONS 316 | 317 | How to Apply These Terms to Your New Programs 318 | 319 | If you develop a new program, and you want it to be of the greatest 320 | possible use to the public, the best way to achieve this is to make it 321 | free software which everyone can redistribute and change under these terms. 322 | 323 | To do so, attach the following notices to the program. It is safest 324 | to attach them to the start of each source file to most effectively 325 | convey the exclusion of warranty; and each file should have at least 326 | the "copyright" line and a pointer to where the full notice is found. 327 | 328 | 329 | Copyright (C) 330 | 331 | This program is free software; you can redistribute it and/or modify 332 | it under the terms of the GNU General Public License as published by 333 | the Free Software Foundation; either version 2 of the License, or 334 | (at your option) any later version. 335 | 336 | This program is distributed in the hope that it will be useful, 337 | but WITHOUT ANY WARRANTY; without even the implied warranty of 338 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 339 | GNU General Public License for more details. 340 | 341 | You should have received a copy of the GNU General Public License 342 | along with this program; if not, write to the Free Software 343 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 344 | 345 | 346 | Also add information on how to contact you by electronic and paper mail. 347 | 348 | If the program is interactive, make it output a short notice like this 349 | when it starts in an interactive mode: 350 | 351 | Gnomovision version 69, Copyright (C) year name of author 352 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 353 | This is free software, and you are welcome to redistribute it 354 | under certain conditions; type `show c' for details. 355 | 356 | The hypothetical commands `show w' and `show c' should show the appropriate 357 | parts of the General Public License. Of course, the commands you use may 358 | be called something other than `show w' and `show c'; they could even be 359 | mouse-clicks or menu items--whatever suits your program. 360 | 361 | You should also get your employer (if you work as a programmer) or your 362 | school, if any, to sign a "copyright disclaimer" for the program, if 363 | necessary. Here is a sample; alter the names: 364 | 365 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 366 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 367 | 368 | , 1 April 1989 369 | Ty Coon, President of Vice 370 | 371 | This General Public License does not permit incorporating your program into 372 | proprietary programs. If your program is a subroutine library, you may 373 | consider it more useful to permit linking proprietary applications with the 374 | library. If this is what you want to do, use the GNU Library General 375 | Public License instead of this License. 376 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | MMCU=msp430g2553 3 | PRG=boot430 4 | 5 | CC=msp430-gcc 6 | CFLAGS=-Os -Wall -mmcu=$(MMCU) -ffunction-sections -fdata-sections -fno-inline-small-functions --cref -Wl,--relax -Wl,-Ttext=0xf000 7 | AFLAGS=-Wa,--gstabs -Wall -mmcu=$(MMCU) -x assembler-with-cpp 8 | 9 | OBJS=$(PRG).o bbusb_packet.o bbusb_protocol.o bbusb_receive.o bbusb_transmit.o 10 | 11 | all: $(OBJS) 12 | $(CC) $(CFLAGS) -o $(PRG).elf $(OBJS) 13 | 14 | size: 15 | msp430-size --totals $(PRG).elf 16 | 17 | hex: $(PRG).elf 18 | msp430-objcopy -O ihex $(PRG).elf $(PRG).hex 19 | 20 | lst: $(PRG).elf 21 | msp430-objdump -DS $(PRG).elf > $(PRG).lst 22 | 23 | flash: 24 | mspdebug rf2500 "prog $(PRG).elf" 25 | 26 | %.o: %.S 27 | $(CC) $(AFLAGS) -c $< 28 | 29 | %.o: %.c 30 | $(CC) $(CFLAGS) -c $< 31 | 32 | clean: 33 | rm -fr $(PRG).elf $(PRG).lst $(PRG).hex $(OBJS) 34 | -------------------------------------------------------------------------------- /Makefile.hid: -------------------------------------------------------------------------------- 1 | 2 | MMCU=msp430g2553 3 | #MMCU=msp430g2452 4 | PRG=hid430 5 | 6 | # Uncomment next line if you're using a 32768 Hz XTAL 7 | #USER_DEFINES=-DUSE_32768HZ_XTAL 8 | 9 | CC=msp430-gcc 10 | CFLAGS=-Os -Wall -mmcu=$(MMCU) -ffunction-sections -fdata-sections -fno-inline-small-functions -Wl,-Map=bbusb.map,--cref -Wl,--relax $(USER_DEFINES) 11 | 12 | AFLAGS=-Wa,--gstabs -Wall -mmcu=$(MMCU) -x assembler-with-cpp 13 | 14 | OBJS=$(PRG).o bbusb_packet.o bbusb_protocol_hid.o bbusb_receive.o bbusb_transmit.o 15 | 16 | all: $(OBJS) 17 | $(CC) $(CFLAGS) -o $(PRG).elf $(OBJS) 18 | 19 | size: 20 | msp430-size --totals $(PRG).elf 21 | 22 | hex: $(PRG).elf 23 | msp430-objcopy -O ihex $(PRG).elf $(PRG).hex 24 | 25 | lst: $(PRG).elf 26 | msp430-objdump -DS $(PRG).elf > $(PRG).lst 27 | 28 | flash: 29 | mspdebug rf2500 "prog $(PRG).elf" 30 | 31 | %.o: %.S 32 | $(CC) $(AFLAGS) -c $< 33 | 34 | %.o: %.c 35 | $(CC) $(CFLAGS) -c $< 36 | 37 | clean: 38 | rm -fr $(PRG).elf $(PRG).lst $(PRG).hex $(OBJS) 39 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | boot430 0.91 3 | 4 | October 2013 v0.91a, add "hid mouse" example build along w/ bootloader function 5 | October 2013 v0.91, stability improvements 6 | chris chung (simpleavr) Feburary 2013 v0.90 7 | 8 | CREDITS: 9 | 10 | based on works from; 11 | . Matthias Koch, Mecrimus-B, provides orginal assembler usb implementation 12 | . Kevin Timmerman, oPossum, provides TI ccs v4 translation on usb implementation 13 | . David Grimbichler, theprophet, enhance transfer timing and correct detail message formats 14 | . Chris Chung, simpleavr, www.simpleavr.com, provides mspgcc translation 15 | and bootloader application logic 16 | . Christian Starkjohann, OBJECTIVE DEVELOPMENT Software GmbH, www.obdev.at 17 | reference hid bootloader project, commandline code framework used in this project 18 | 19 | please see License.txt for licensing 20 | 21 | DESCRIPTION: 22 | 23 | . boot430 is usb bootloader for certain (8k and 16k) msp430g2xxx value line devices. 24 | . based on bbusb (for bit-bang usb), a v-usb like low-speed usb implementaion on msp430 25 | . requires a minimal component circuit and is very breadboard friendly. 26 | . can be used for other usb implementations, by replacing bbusb_prototcol.c and main() 27 | . there are many alternate h/w hookups, research "v-usb 3.3v" 28 | . compile w/ mspgcc, works on linux and windows w/ cygwin 29 | . requires libusb 30 | * (new v0.91a) add new Makefile.hid to build a simple hid mouse instead of a complex bootloader 31 | 32 | SCHEMATIC: 33 | MSP430G2xxx Vcc (3.3v) 34 | Vcc ----------------- /|\ 35 | /|\ | | | ___ 36 | | | | | / \ LP2950AC3.3 37 | | | | Vcc +-----o__o__o------ 38 | .-. | | /|\ | Out | In | 39 | 4.7k | | | | | | | | 40 | | | | | | --| |----+---| |--+ 41 | .-. | | .-. 10uF | 0.1uF | 42 | | | | | | 1.5k | ----------o Vusb (5v) 43 | ----|RST | | | | 44 | ----|P2.6 | .-. -------------------o Gnd 45 | | | | | 46 | led \ / | P1.1|--+-[ 68ohm ]--------------------------------o D- 47 | --- | | 48 | | | P1.0|----[ 68ohm ]--------------------------------o D+ 49 | ----|P2.7 | 50 | 51 | * led is optional, if used, better attach a series resistor of a few hundred ohms for reliability 52 | * LP2950 can be replaced by similar 3.3v LDO regulator (try 3.6v LDO to improve reliability) 53 | 54 | FEATURES: 55 | 56 | . occupies 2.4k flash space 57 | . requires no external crystal, timer sychronize via usb sync frame 58 | . v-usb like circuitry, BOM (68ohm x 2, 1.5k, 4.7k, LP2950AC3.3, 10uF, 0.1uF, led) 59 | . supports 8k and 16k msp430g2xxx value line devices 60 | . bootloader checks for D- pull-up and usb host presence upon bootup 61 | 62 | NOTES: 63 | . change MCU= in Makefiles for target device (g2553, g2342 tested) 64 | . commandline contains host side bootloader code 65 | . apps directory contains sample applications to test firmware bootloading 66 | 67 | (2013.10.xx) 68 | . there is no change in bootloader except toogle_syncled() disabled 69 | . add files and build mechanism for a simple hid mouse application (no bootloader) 70 | . use Makefile.hid instead of Makefile, sample "hid430.hex" firmware included 71 | . to build and flash, (1) make -f Makefile.hid, (2) make -f Makefile.hid flash 72 | . please view and change Makefiles to reflect your device (MMCU) 73 | 74 | (2013.10.xx) 75 | 2013.10 changes this v0.91 mainly contributed by David Grimbichler aka "theprophet" 76 | 77 | . David tried v0.90 and had numerous issues 78 | . had provided various fixes to enable reliability on various platforms 79 | . implement correct report_id according to usb standards 80 | . implement a much more reliable timing scheme for data flashing and transfer 81 | . bootloader is a bit slower but much more reliable 82 | * if you use a led "heartbeat" blinker between P2.6 and P2.7, be sure to use a resistor 83 | * if you have a choice, use a 3.6V LDO for better reliability 84 | * if you need help, find the appropriate thread in 43oh.com forum, most authors frequent that 85 | * now include binary excutable, Windows apps loader "commandline/boot430load.exe" 86 | * and bootloader hex firmware "boot430.hex" 87 | 88 | 89 | (2012.12.xx) 90 | . it started from a thread post in 43oh.com, look for "bit-bang usb" 91 | . Macrimus-B posted code on a bit-bang usb implementation for msp430 92 | . oPossum translate assembler code to TI CCS, w/ simplier C entry points 93 | . myself translate code into mspgcc, implements this bootloader on top 94 | 95 | (2013.02.05) 96 | . initial checkin 97 | 98 | -------------------------------------------------------------------------------- /apps/Makefile: -------------------------------------------------------------------------------- 1 | MMCU=msp430g2553 2 | #MMCU=msp430g2432 3 | 4 | CC=msp430-gcc 5 | CFLAGS=-Os -Wall -mmcu=$(MMCU) -ffunction-sections -fdata-sections -fno-inline-small-functions --cref -Wl,--relax 6 | 7 | TARGETS = rgb.hex segled.hex simple_blinky.hex 8 | 9 | all: $(TARGETS) 10 | 11 | %.hex: %.elf 12 | msp430-objcopy -O ihex $< $@ 13 | 14 | %.elf: %.c 15 | $(CC) $(CFLAGS) -o $@ $< 16 | 17 | clean: 18 | rm -fr *.elf *.lst *.hex *.o 19 | -------------------------------------------------------------------------------- /apps/rgb.c: -------------------------------------------------------------------------------- 1 | //****************************************************************************** 2 | // MSP430F20xx Demo - RGB LED 3 | // 4 | // Description; RGB LED via P1.0-3, Tactile Button via P2.7 5 | // ACLK = n/a, MCLK = SMCLK = default DCO 6 | // 7 | // MSP430F20xx 8 | // ----------------- 9 | // /|\| XIN|- 10 | // | | | 11 | // --|RST P2.3|-->Button in 12 | // | P2.5|-->Button (-) out 13 | // | | 14 | // | P2.2|-->LED-G 15 | // | P2.1|-->LED-B 16 | // | P2.0|-->LED-Common 17 | // | P1.5|-->LED-R 18 | /* 19 | Vc Gnd 20 | +=====================================================+ 21 | | . . . . . . . . . . . . . . . . . | 22 | | . . . . . . . . . . . . . . . . . | 23 | | . . . . . . . . . . . . . . . . . | 24 | | . v . . . . . . . . . . . . . . . | 25 | | . . ---+--+--+--+--+--+--+--+--+ . . . . . | connect v to v 26 | | |- b6 b7 CK IO a7 a6 b5 b4 b3| | 27 | | |+ a0 a1 a2 a3 a4 a5 b0 b1 b2| | 28 | | . . ---+--+--+--+--+--+--+--+--+ . . . . . | 29 | | . . v . . . . . R (c) G B . . . . . | 30 | | . . . . . . . . . . . . . . . . . | 31 | | . . . . . . . . . . . . . . . . . | 32 | | . . . . . . . . . . . . . . . . . | 33 | +=====================================================+ 34 | 35 | */ 36 | // 37 | // CChung 38 | // Giftware, no license, no warranty 39 | // July 2010 40 | // Built with msp430-gcc 41 | //****************************************************************************** 42 | 43 | #include 44 | #include 45 | 46 | volatile uint8_t rgb=7; 47 | 48 | void main(void) { 49 | WDTCTL = WDTPW + WDTHOLD; // Stop WDT 50 | 51 | BCSCTL1 = CALBC1_1MHZ; 52 | DCOCTL = CALDCO_1MHZ; 53 | 54 | P1DIR = BIT5; 55 | P2DIR = BIT0|BIT1|BIT2|BIT3; 56 | 57 | CCTL0 = CCIE; // CCR0 interrupt enabled 58 | CCR0 = 100; 59 | TACTL = TASSEL_2 + MC_1; // SMCLK, upmode 60 | 61 | P2SEL = 0x00; 62 | //P2REN = 0xc0; 63 | P2REN = BIT5; 64 | 65 | uint8_t button=0; 66 | 67 | _BIS_SR(GIE); 68 | while (1) { 69 | if (P2IN&BIT5) { 70 | if (button > 5) { // button released 71 | rgb++; 72 | }//if 73 | button = 0; 74 | }//if 75 | else { 76 | button++; 77 | }//else 78 | }//while 79 | } 80 | 81 | volatile uint8_t clicks=0; 82 | volatile uint8_t ticks=0; 83 | // Timer A0 interrupt service routine 84 | #pragma vector=TIMER0_A0_VECTOR 85 | __interrupt void Timer_A (void) { 86 | clicks++; 87 | if (clicks&0x03) { 88 | P1OUT = 0x00; 89 | }//if 90 | else { 91 | P2OUT = 0; 92 | P1OUT = 0; 93 | //_________ trying to compsensate for individual color brightness 94 | if (rgb&0x04) P1OUT |= BIT5; 95 | if (rgb&0x02) P2OUT |= BIT2; 96 | if (rgb&0x01) P2OUT |= BIT1; 97 | ticks++; 98 | if (!ticks) rgb++; 99 | }//else 100 | } 101 | 102 | -------------------------------------------------------------------------------- /apps/segled.c: -------------------------------------------------------------------------------- 1 | // 2 | // Description; 3 | // 7 segment led examples 4 | // 5 | // 6 | /* 7 | MSP430 20pin 8 | 9 | Vc Gnd 10 | +=====================================================+ 11 | | . . . . . . . . . . . . . . . . . | 12 | | . . . . . . . . . . . . . . . . . | 13 | | . . . . . . c . . . . . . . . . . | connect c to c 14 | | . v . . . . . . . . . . . . . . . | 15 | | . . ---+--+--+-(0)-A--F-(1)(2)-B--+--+--+ . . | connect v to v 16 | | |- b6 b7 CK IO a7 a6 b5 b4 b3| | | 17 | | |+ a0 a1 a2 a3 a4 a5 b0 b1 b2| | | 18 | | . . --+--+--+--+--+--+--+--+--+- . . | . . | 19 | | . . . + - - E D (.) C G (3) - - + . . | 20 | | . . v . c . . . . . . . . . . . . | 21 | | . . +--B--+ . . +. . . . . . . . . . | +--B--+ tactile button 22 | | . . . . . . +Bz+ . . . . . . . . . | +Bz+ buzzer 23 | +=====================================================+ 24 | 25 | MSP430 20pin (reverse) 26 | 27 | Vc Gnd 28 | +=====================================================+ 29 | | . . . . . . . . . . . . . . . . . | 30 | | . . . . . . . . . . . . . . . . . | 31 | | . . . . . . c . . . . . . . . . . | 32 | | . . . . . . . . . . . . . . . . . | 33 | | . . ---+--+--+-(3) G C (.) D E | 34 | | |- b6 b7 CK IO a7 a6 b5 b4 b3| | 35 | | |+ a0 a1 a2 a3 a4 a5 b0 b1 b2| | 36 | | . . --+--+--+--+--+--+--+--+--+- . . . . . | 37 | | . . . . . . B (2)(1) F A 0 . . . . . | 38 | | . . v . c . . . . . . . . . . . . | 39 | | . . +--B--+ . . +. . . . . . . . . . | +--B--+ tactile button 40 | | . . . . . . +Bz+ . . . . . . . . . | +Bz+ buzzer 41 | +=====================================================+ 42 | 43 | 44 | 45 | */ 46 | 47 | 48 | #define DEVICE_20P // uncomment for 20 pin devices 49 | #define DEVICE_REVERSE 50 | #define LED_3DIGITS 51 | #define LED_COMMONANODE 52 | 53 | #include 54 | 55 | #include 56 | #include 57 | 58 | 59 | #define NO_TEMP_CHOICE 60 | //#define METRIC_TEMP // uncomment for oC 61 | 62 | #ifdef DEVICE_20P 63 | 64 | //____ this is the pin map for 20pin devices, i just shift the led module right 3 steps 65 | #ifdef DEVICE_REVERSE 66 | 67 | #define SEG_A_P1 0 68 | #define SEG_B_P1 (1<<3) 69 | #define SEG_C_P1 (1<<6) 70 | #define SEG_D_P1 0 71 | #define SEG_E_P1 0 72 | #define SEG_F_P1 0 73 | #define SEG_G_P1 (1<<7) 74 | #define SEG_d_P1 0 75 | #define DIGIT_0_P1 0 76 | #define DIGIT_1_P1 (1<<5) 77 | #define DIGIT_2_P1 (1<<4) 78 | #define DIGIT_3_P1 (1<<1) 79 | 80 | #define SEG_A_P2 (1<<1) 81 | #define SEG_B_P2 0 82 | #define SEG_C_P2 0 83 | #define SEG_D_P2 (1<<4) 84 | #define SEG_E_P2 (1<<3) 85 | #define SEG_F_P2 (1<<0) 86 | #define SEG_G_P2 0 87 | #define SEG_d_P2 (1<<5) 88 | #define DIGIT_0_P2 (1<<2) 89 | #define DIGIT_1_P2 0 90 | #define DIGIT_2_P2 0 91 | #define DIGIT_3_P2 0 92 | 93 | #else 94 | 95 | #define SEG_A_P1 (1<<7) 96 | #define SEG_B_P1 0x00 97 | #define SEG_C_P1 0x00 98 | #define SEG_D_P1 (1<<4) 99 | #define SEG_E_P1 (1<<3) 100 | #define SEG_F_P1 (1<<6) 101 | #define SEG_G_P1 0x00 102 | #define SEG_d_P1 (1<<5) 103 | //#define DIGIT_0_P1 (1<<1) 104 | #define DIGIT_0_P1 0x00 105 | #define DIGIT_1_P1 0x00 106 | #define DIGIT_2_P1 0x00 107 | #define DIGIT_3_P1 0x00 108 | 109 | #define SEG_A_P2 0x00 110 | #define SEG_B_P2 (1<<3) 111 | #define SEG_C_P2 (1<<0) 112 | #define SEG_D_P2 0x00 113 | #define SEG_E_P2 0x00 114 | #define SEG_F_P2 0x00 115 | #define SEG_G_P2 (1<<1) 116 | #define SEG_d_P2 0x00 117 | #define DIGIT_0_P2 0x00 118 | #define DIGIT_1_P2 (1<<5) 119 | #define DIGIT_2_P2 (1<<4) 120 | #define DIGIT_3_P2 (1<<2) 121 | 122 | #endif 123 | 124 | //#define BTNP_P1 (1<<1) // button uses p1.1 125 | #define BTNP_P1 (1<<6) // button uses p1.1 126 | #define _P2DIR (1<<7) // we want to try use 32khz crystal 127 | 128 | 129 | #else 130 | 131 | //____ this is the original pin map for 14pin devices 132 | 133 | #define SEG_A_P1 0x00 134 | #define SEG_B_P1 (1<<6) 135 | #define SEG_C_P1 (1<<3) 136 | #define SEG_D_P1 (1<<1) 137 | #define SEG_E_P1 (1<<0) 138 | #define SEG_F_P1 0x00 139 | #define SEG_G_P1 (1<<4) 140 | #define SEG_d_P1 (1<<2) 141 | #define DIGIT_0_P1 0x00 142 | #define DIGIT_1_P1 (1<<2) 143 | #define DIGIT_2_P1 (1<<7) 144 | #define DIGIT_3_P1 (1<<5) 145 | 146 | #define SEG_A_P2 (1<<7) 147 | #define SEG_B_P2 0x00 148 | #define SEG_C_P2 0x00 149 | #define SEG_D_P2 0x00 150 | #define SEG_E_P2 0x00 151 | #define SEG_F_P2 (1<<6) 152 | #define SEG_G_P2 0x00 153 | #define SEG_d_P2 0x00 154 | #define DIGIT_0_P2 (1<<6) 155 | #define DIGIT_1_P2 0x00 156 | #define DIGIT_2_P2 0x00 157 | #define DIGIT_3_P2 0x00 158 | 159 | #define BTNP_P1 (1<<2) // button uses p1.2 160 | #define _P2DIR 0 161 | 162 | #endif 163 | // calcuate number of segments on individual digits, letters show 164 | // will use to decide how long a digit / letter stays "on" 165 | #define SEGS_STAY(v) \ 166 | (((v & (1<<6)) ? 1 : 0) +\ 167 | ((v & (1<<5)) ? 1 : 0) +\ 168 | ((v & (1<<4)) ? 1 : 0) +\ 169 | ((v & (1<<3)) ? 1 : 0) +\ 170 | ((v & (1<<2)) ? 1 : 0) +\ 171 | ((v & (1<<1)) ? 1 : 0) +\ 172 | ((v & (1<<0)) ? 1 : 0)) | 0x20 173 | 174 | // macro magic 175 | // what the io ports output for individual digits / letters 176 | // we do this at compile time so that we don't need to use runtime cycles 177 | // to map segment and port pins 178 | #define SEGS_PORT_DET(p, v) \ 179 | (((v & (1<<6)) ? SEG_A_P##p : 0) | \ 180 | ((v & (1<<5)) ? SEG_B_P##p : 0) | \ 181 | ((v & (1<<4)) ? SEG_C_P##p : 0) | \ 182 | ((v & (1<<3)) ? SEG_D_P##p : 0) | \ 183 | ((v & (1<<2)) ? SEG_E_P##p : 0) | \ 184 | ((v & (1<<1)) ? SEG_F_P##p : 0) | \ 185 | ((v & (1<<0)) ? SEG_G_P##p : 0)) 186 | 187 | #define SEGS_PORT(v) {SEGS_STAY(v),SEGS_PORT_DET(1, v),SEGS_PORT_DET(2, v)} 188 | // port 1/2 pins used to turn segments on, led anodes 189 | #define SEGS_1 (SEG_A_P1|SEG_B_P1|SEG_C_P1|SEG_D_P1|SEG_E_P1|SEG_F_P1|SEG_G_P1) 190 | #define SEGS_2 (SEG_A_P2|SEG_B_P2|SEG_C_P2|SEG_D_P2|SEG_E_P2|SEG_F_P2|SEG_G_P2|SEG_d_P2) 191 | 192 | // port 1/2 pins used turn digits on, led cathodes 193 | #define DIGITS_1 (DIGIT_0_P1|DIGIT_1_P1|DIGIT_2_P1|DIGIT_3_P1) 194 | #define DIGITS_2 (DIGIT_0_P2|DIGIT_1_P2|DIGIT_2_P2|DIGIT_3_P2) 195 | 196 | // port 1/2 pins used 197 | #define USED_1 (SEGS_1|DIGITS_1) 198 | #define USED_2 (SEGS_2|DIGITS_2) 199 | 200 | /* 201 | ___a__ 202 | | | 203 | f| | b 204 | ___g__ 205 | e| | c 206 | | | 207 | ___d__ 208 | */ 209 | // composition of digits and letters we need 210 | //_____________________ abc defg 211 | #define LTR_0 0x7e // 0111 1110 212 | #define LTR_1 0x30 // 0011 0000 213 | #define LTR_2 0x6d // 0110 1101 214 | #define LTR_3 0x79 // 0111 1001 215 | #define LTR_4 0x33 // 0011 0011 216 | #define LTR_5 0x5b // 0101 1011 217 | #define LTR_6 0x5f // 0101 1111 218 | #define LTR_7 0x70 // 0111 0000 219 | #define LTR_8 0x7f // 0111 1111 220 | #define LTR_9 0x7b // 0111 1011 221 | #define BLANK 0x00 // 0000 0000 222 | #define BAR_1 0x40 // 0100 0000 223 | #define BAR_2 0x01 // 0000 0001 224 | #define BAR_3 (BAR_1|BAR_2) 225 | #define LTRdg 0x63 // 0110 0011 226 | #define LTR_C 0x4e // 0100 1110 227 | 228 | #define LTR_c 0x4e // 0000 1101 229 | #define LTR_A 0x77 // 0111 0111 230 | #define LTR_b 0x1f // 0001 1111 231 | #define LTR_J 0x3c // 0011 1100 232 | #define LTR_L 0x0e // 0000 1110 233 | #define LTR_S 0x5b // 0101 1011 234 | #define LTR_E 0x4f // 0100 1111 235 | #define LTR_t 0x0f // 0000 1111 236 | #define LTR_n 0x15 // 0001 0101 237 | #define LTR_d 0x3d // 0011 1101 238 | #define LTR_i 0x10 // 0001 0000 239 | #define LTR_H 0x37 // 0011 0111 240 | #define LTR_r 0x05 // 0000 0101 241 | #define LTR_o 0x1d // 0001 1101 242 | #define LTR_f 0x47 // 0100 0111 243 | #define LTRml 0x66 // 0110 0110 244 | #define LTRmr 0x72 // 0111 0010 245 | #define LTR__ 0x00 // 0000 0000 246 | 247 | // port io values for individual digits / letters 248 | // 1st byte cycles to stay 249 | // 2nd byte port 1 value 250 | // 3rd byte port 2 value 251 | static const uint8_t digit2ports[][3] = { 252 | SEGS_PORT(LTR_0), SEGS_PORT(LTR_1), SEGS_PORT(LTR_2), SEGS_PORT(LTR_3), 253 | SEGS_PORT(LTR_4), SEGS_PORT(LTR_5), SEGS_PORT(LTR_6), SEGS_PORT(LTR_7), 254 | SEGS_PORT(LTR_8), SEGS_PORT(LTR_9), SEGS_PORT(BLANK), SEGS_PORT(LTR_o), 255 | SEGS_PORT(BAR_2), SEGS_PORT(LTR_b), SEGS_PORT(LTR_f), SEGS_PORT(LTR_C), 256 | SEGS_PORT(LTR_t), SEGS_PORT(LTR_H), SEGS_PORT(LTR_n), SEGS_PORT(LTR_r), 257 | SEGS_PORT(LTR_J), SEGS_PORT(LTR_d), SEGS_PORT(LTR_L), SEGS_PORT(LTR_i), 258 | SEGS_PORT(LTR_E), SEGS_PORT(LTR_A), 259 | }; 260 | 261 | // digits / letters we are using 262 | enum { 263 | POS_0, POS_1, POS_2, POS_3, POS_4, POS_5, POS_6, POS_7, 264 | POS_8, POS_9, POS__, POS_o, POSb2, POS_b, POS_f, POS_C, 265 | POS_t, POS_H, POS_n, POS_r, POS_J, POS_d, POS_L, POS_i, 266 | POS_E, POS_A, 267 | }; 268 | 269 | // storage for multiplexing, 3 bytes output x 4 digits 270 | uint8_t output[3 * 4]; 271 | 272 | // loads data into output[] for immediate led multiplexing 273 | //__________________________________________________ 274 | void seg2port(uint16_t val) { 275 | 276 | #ifdef LED_3DIGITS 277 | uint8_t which = 2; 278 | #else 279 | uint8_t which = 3; 280 | #endif 281 | do { 282 | uint8_t *pp = output + which * 3; 283 | uint8_t offset = 3; 284 | uint8_t digit = val % 10; 285 | if (val) val /= 10; 286 | do { 287 | *pp++ = digit2ports[digit][--offset]; 288 | } while (offset); 289 | } while (which--); 290 | 291 | } 292 | 293 | volatile uint8_t ticks=0; 294 | 295 | //______________________________________________________________________ 296 | void main(void) { 297 | 298 | WDTCTL = WDTPW + WDTHOLD; 299 | 300 | BCSCTL1 = CALBC1_1MHZ; // Set DCO to 1MHz 301 | DCOCTL = CALDCO_1MHZ; 302 | 303 | CCTL0 = CCIE; // CCR0 interrupt enabled 304 | CCR0 = 50000; 305 | TACTL = TASSEL_2 + MC_1; // SMCLK, upmode 306 | _BIS_SR(GIE); 307 | 308 | /* 309 | P1DIR = BIT3|BIT4; 310 | P1OUT = 0; 311 | P1OUT = BIT4; 312 | while (1) { asm("nop"); } 313 | */ 314 | uint8_t stays=0; 315 | uint16_t cnt=0; 316 | 317 | uint8_t pos=0; 318 | static const uint8_t digit_map1[] = { DIGIT_0_P1, DIGIT_1_P1, DIGIT_2_P1, DIGIT_3_P1, }; 319 | static const uint8_t digit_map2[] = { DIGIT_0_P2, DIGIT_1_P2, DIGIT_2_P2, DIGIT_3_P2, }; 320 | while (1) { 321 | 322 | 323 | // allow led segments stays on 324 | if (stays & 0x0f) { stays--; continue; } 325 | // turn off all io pins, led blanks 326 | P2DIR = 0; P1DIR = 0; 327 | P2OUT = 0; P1OUT = 0; 328 | // allow led segments stays blank out, dimming 329 | stays >>= 2; // adjust 330 | if (stays) { stays--; continue; } 331 | 332 | pos &= 0x03; 333 | 334 | if (!pos) { 335 | if (ticks >= 5) { 336 | seg2port(cnt++); 337 | ticks = 0; 338 | }//if 339 | }//if 340 | 341 | //___________ load segments and turn on 1 of 4 digits 342 | uint8_t *ioptr = output + (pos*3); 343 | 344 | #ifdef LED_COMMONANODE 345 | P2OUT = ~(*ioptr & ~digit_map2[pos]); 346 | #else 347 | P2OUT = *ioptr & ~digit_map2[pos]; 348 | #endif 349 | P2DIR = (*ioptr++ | digit_map2[pos]) | _P2DIR; 350 | #ifdef LED_COMMONANODE 351 | P1OUT = ~(*ioptr & ~digit_map1[pos]); 352 | #else 353 | P1OUT = *ioptr & ~digit_map1[pos]; 354 | #endif 355 | P1DIR = *ioptr++ | digit_map1[pos]; 356 | stays = *ioptr; 357 | 358 | pos++; 359 | 360 | }//while 361 | 362 | } 363 | 364 | //______________________________________________________________________ 365 | #pragma vector=ADC10_VECTOR 366 | __interrupt void ADC10_ISR(void) { 367 | __bic_SR_register_on_exit(CPUOFF); // Clear CPUOFF bit from 0(SR) 368 | } 369 | 370 | //______________________________________________________________________ 371 | #pragma vector=TIMER0_A0_VECTOR 372 | __interrupt void TIMER0_A0_ISR(void) { 373 | ticks++; 374 | //_BIC_SR_IRQ(LPM3_bits); 375 | } 376 | 377 | 378 | -------------------------------------------------------------------------------- /apps/simple_blinky.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | void main(void) 6 | { 7 | WDTCTL = WDTPW + WDTHOLD; 8 | BCSCTL1 = CALBC1_1MHZ; 9 | DCOCTL = CALDCO_1MHZ; 10 | 11 | P2SEL = 0; 12 | P1DIR = 0xFF; 13 | P2DIR = BIT6|BIT7; 14 | P1OUT = 0; 15 | P2OUT = 0; 16 | 17 | for(;;) 18 | { 19 | P1OUT ^= 0xFF; 20 | P2OUT ^= BIT6; 21 | __delay_cycles(1000000); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /apps/simple_blinky.hex: -------------------------------------------------------------------------------- 1 | :10C000005542200135D0085A8245000231400004D3 2 | :10C010003F4000000F9308249242000220012F832A 3 | :10C020009F4F94C00002F8233F4000000F93072465 4 | :10C030009242000220011F83CF430002F923B24045 5 | :10C04000805A2001D242FF105700D242FE10560003 6 | :10C05000C2432E00F2432200F240C0FF2A00C24336 7 | :10C060002100C24329005F4221007FE3C24F21002B 8 | :10C07000F2E0400029003E4006003F400E161F83BC 9 | :10C08000FE231E83FC23EF3F32D0F000FD3F304003 10 | :04C0900092C0001347 11 | :10FFE0008EC08EC08EC08EC08EC08EC08EC08EC0A1 12 | :10FFF0008EC08EC08EC08EC08EC08EC08EC000C01F 13 | :040000030000C00039 14 | :00000001FF 15 | -------------------------------------------------------------------------------- /bbusb.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | // bbusb_protocol.c 5 | const uint8_t *ProtocolSetupPacket(uint8_t *); 6 | void IrqIn(uint8_t *); 7 | 8 | // bbusb_packet.c 9 | void CRC(uint8_t *); 10 | void PacketGenerator(void); 11 | 12 | // --- USB PID values 13 | // Token 14 | #define USB_PID_OUT 0xE1 15 | #define USB_PID_IN 0x69 16 | //USB_PID_SOF 0xA5 17 | #define USB_PID_SETUP 0x2D 18 | // Data 19 | #define USB_PID_DATA0 0xC3 20 | #define USB_PID_DATA1 0x4B 21 | //USB_PID_DATA2 0x87 // HS only 22 | //USB_PID_MDATA 0x0F // HS only 23 | // Handshake 24 | #define USB_PID_ACK 0xD2 25 | #define USB_PID_NAK 0x5A 26 | #define USB_PID_STALL 0x1E 27 | //USB_PID_NYET 0x96 28 | // Special 29 | //USB_PID_PRE 0x3C 30 | //USB_PID_ERR 0x3C 31 | //USB_PID_SPLIT 0x78 32 | //USB_PID_PING 0xB4 33 | 34 | 35 | #define usbout P1OUT 36 | #define usbdir P1DIR 37 | #define usbin P1IN 38 | #define usbifg P1IFG 39 | #define usbie P1IE 40 | #define usbies P1IES 41 | 42 | #define usbplus BIT0 // P1.0 D+ over 50 Ohms 43 | #define usbminus BIT1 // P1.1 D- over 50 Ohms with 1.5 kOhm pullup hardwired to Vcc. 44 | 45 | #define nop2 jmp $ + 2 46 | 47 | #define toggle_syncled xor.b #BIT2, &P1OUT // Toggles Sync LED, good for triggering an oscilloscope and visual feedback 48 | // Preserve clock cycles if you want to remove this ! 49 | -------------------------------------------------------------------------------- /bbusb.inc: -------------------------------------------------------------------------------- 1 | 2 | #define USE_32768HZ_XTAL 3 | 4 | #define USB_PID_OUT 0xE1 5 | #define USB_PID_IN 0x69 6 | //USB_PID_SOF 0xA5 7 | #define USB_PID_SETUP 0x2D 8 | // Data 9 | #define USB_PID_DATA0 0xC3 10 | #define USB_PID_DATA1 0x4B 11 | //USB_PID_DATA2 0x87 // HS only 12 | //USB_PID_MDATA 0x0F // HS only 13 | // Handshake 14 | #define USB_PID_ACK 0xD2 15 | #define USB_PID_NAK 0x5A 16 | #define USB_PID_STALL 0x1E 17 | //USB_PID_NYET 0x96 18 | // Special 19 | //USB_PID_PRE 0x3C 20 | //USB_PID_ERR 0x3C 21 | //USB_PID_SPLIT 0x78 22 | //USB_PID_PING 0xB4 23 | 24 | 25 | #define usbout P1OUT 26 | #define usbdir P1DIR 27 | #define usbin P1IN 28 | #define usbifg P1IFG 29 | #define usbie P1IE 30 | #define usbies P1IES 31 | 32 | #define usbplus BIT0 // P1.0 D+ over 50 Ohms 33 | #define usbminus BIT1 // P1.1 D- over 50 Ohms with 1.5 kOhm pullup hardwired to Vcc. 34 | 35 | #define nop2 jmp $ + 2 36 | 37 | //#define toggle_syncled xor.b #BIT2, &P1OUT // Toggles Sync LED, good for triggering an oscilloscope and visual feedback 38 | // Preserve clock cycles if you want to remove this ! 39 | .macro toggle_syncled ; 40 | nop2 41 | nop2 42 | .endm 43 | 44 | #define CRC_STYLE 1 // 0: On-the-fly CRC calculation - fastest, but largest code 45 | // 1: Bitwise loop CRC calculation - smallest and slowest 46 | // 2: Bitwise unrolled loop CRC calculation - small and faster 47 | // 3: Table look-up CRC calculation - large and fast 48 | 49 | #if !CRC_STYLE // Disable calls to CRC() if on-the-fly CRC calculation is being used 50 | #define CRC(x) // 51 | #endif // 52 | -------------------------------------------------------------------------------- /bbusb_packet.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2012 Kevin Timmerman 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | // 17 | // Ported to mspgcc by Chris Chung 2012.12 w/ the following changes 18 | // 19 | #include 20 | #include "bbusb.h" 21 | 22 | 23 | static uint8_t SendPacketBuffer[12]; // LEN PID DATA[0...8] CRCL CRCM <- 12 octets max 24 | 25 | unsigned DataToTransmitOffset; 26 | 27 | uint8_t *ReadyForTransmit = 0; 28 | uint8_t *DataToTransmit = 0; 29 | unsigned Data_PID_Toggle = USB_PID_DATA0; 30 | 31 | 32 | void CRC(uint8_t *d) // Append CRC to an outbound USB SIE packet 33 | { // Before: [Length] [PID] [Data 0...8] 34 | // After: [Length] [PID] [Data 0...8] [CRC LSB] [CRC MSB] 35 | uint16_t x; // 36 | uint16_t crc = 0xFFFF; // Init CRC with FFFF 37 | uint8_t *end = d + *d; // Make pointer to last octect of buffer 38 | *d++ += 2; // Add 2 to length - the CRC takes 2 octets 39 | ++d; // Skip length and PID octets, the CRC is of data only 40 | while(d <= end) { // Do all data octets 41 | x = *d++; // Get an octect of data 42 | x ^= crc; crc >>= 8; // Xor with CRC, shift CRC 43 | if(x & 0x01) crc ^= 0xC0C1; // Perform CRC on each bit of (octect ^ CRC) 44 | if(x & 0x02) crc ^= 0xC181; // 45 | if(x & 0x04) crc ^= 0xC301; // 46 | if(x & 0x08) crc ^= 0xC601; // 47 | if(x & 0x10) crc ^= 0xCC01; // 48 | if(x & 0x20) crc ^= 0xD801; // 49 | if(x & 0x40) crc ^= 0xF001; // 50 | if(x & 0x80) crc ^= 0xA001; // 51 | } // 52 | crc ^= 0xFFFF; // Invert CRC 53 | *d++ = crc & 0x00FF; // Append LSB of CRC 54 | *d = crc >> 8; // Append MSB of CRC 55 | } // 56 | 57 | void PacketGenerator(void) // Split outbound USB packets in to chunks of 8 or fewer data octets 58 | { // 59 | // The last packet must have 7 or fewer data octets, all preceding must 60 | // have 8 data octets <<<--- read that again! 61 | // If the last chunk fills the packet (8 data octets) then a packet with 62 | // no data must be sent as the last packet <<<--- understand now? 63 | // 64 | // This should never happen! 65 | //if(ReadyForTransmit || !DataToTransmit) return; 66 | // 67 | // Make pointer to next chunk of data 68 | uint8_t *s = DataToTransmit + DataToTransmitOffset; 69 | // Make pointer to last octet of data 70 | uint8_t *end = DataToTransmit + DataToTransmit[0]; 71 | // 72 | uint8_t *d = SendPacketBuffer + 1; // Make pointer to second octet (PID) of USB SIE packet 73 | // Toggle the DATA PID for each USB SIE packet 74 | *d++ = (Data_PID_Toggle ^= (USB_PID_DATA0 ^ USB_PID_DATA1)); 75 | // 76 | unsigned n = 0; // Init data octet counter 77 | do { // 78 | if(s > end) { // Check if at end of buffer 79 | DataToTransmit = 0; // Nothing more to send >>> and fewer than 8 data octets 80 | // in this packet <<<--- very important! 81 | break; // Stop data copy 82 | } // 83 | *d++ = *s++; // Copy a data octet 84 | } while(++n < 8); // Until up to 8 octets have been copied 85 | // 86 | DataToTransmitOffset += n; // Move to next chunk of data 87 | SendPacketBuffer[0] = n + 1; // Set USB SIE packet length 88 | // 89 | CRC(SendPacketBuffer); // Append CRC to USB SIE packet 90 | // 91 | // Send the packet 92 | ReadyForTransmit = SendPacketBuffer; // The SIE will see the non-NULL pointer and tx the buffer 93 | } // 94 | 95 | -------------------------------------------------------------------------------- /bbusb_protocol.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2012 Kevin Timmerman 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | // 17 | // Ported to mspgcc by Chris Chung 2012.12 w/ the following changes 18 | // . adopt / implements logic from v-usb hid bootloader 19 | // 20 | #include 21 | #include "bbusb.h" 22 | 23 | 24 | extern const uint8_t *ReadyForTransmit; 25 | extern unsigned NewAddress; 26 | extern uint8_t *ReadyForTransmitIrqIn; 27 | extern unsigned Data_PID_ToggleIrqIn; 28 | 29 | 30 | static const uint8_t StatusEmpty[] = { 31 | 0 32 | }; 33 | 34 | static const uint8_t StatusZeroZero[] = { 35 | 2, 0, 0 36 | }; 37 | 38 | static const uint8_t Device_Descriptor[] = { // Mouse Device Descriptor 39 | 18, // Length 40 | 0x12, // bLength 41 | 0x01, // bDescriptorType = Device 42 | 0x10, 0x01, // bcdUSB (USB Spec Rev 1.10) 43 | 0x00, // bDeviceClass 44 | 0x00, // bDeviceSubClass 45 | 0x00, // bDeviceProtocol 46 | 0x08, // bMaxPacketSize0 47 | 0xc0, 0x16, // idVendor 48 | 0xdf, 0x05, // idProduct 49 | 0x01, 0x00, // bcdDevice 50 | 0x01, // iManufactuer (String descriptor index) 51 | 0x02, // iProduct (String descriptor index) 52 | 0x00, // iSerialNumber (String descriptor index) 53 | 0x01 // idNumConfigurations 54 | }; 55 | 56 | static const uint8_t Configuration_Descriptor_first9[] = { 57 | 9, 9, 2, 34, 0, 1, 1, 0, 0x80, 50 58 | }; 59 | 60 | static const uint8_t Configuration_Descriptor_complete[] = { 61 | 34, // Length 62 | // - Config Descriptor 63 | 9, // bLength 64 | 2, // bDescriptorType = Configuration 65 | 34, 0, // wTotalLength 66 | 1, // bNumInterfaces 67 | 1, // bConfigurationValue (Used by Set Configuration request) 68 | 0, // iConfiguration (String descriptor for this configuration) 69 | 0x80, // bmAttributes 70 | 50, // bMaxPower (in units of 2 mA) 71 | // - Interface Descriptor 72 | 9, // bLength 73 | 4, // bDescriptorType = Interface 74 | 0, // bInterfaceNumber 75 | 0, // bAlternateSetting 76 | 1, // bNumEndpoints 77 | 3, // bInterfaceClass = HID 78 | 0, // bInterfaceSubClass = Boot 79 | 0, // bInterfaceProtocol = Mouse 80 | 0, // iInterface (String descriptor for this interface) 81 | // - HID Descriptor 82 | 9, // bLength 83 | 0x21, // bDescriptorType = HID 84 | 0x01, 0x01, // bcdHID (Class Spec Version 1.10) 85 | 0, // bCountryCode 86 | 1, // bNumDescriptors 87 | 34, // bDescriptorType = Report 88 | 33, 0, // wDescriptorLength 89 | // - Endpoint Descriptor 90 | 7, // bLength 91 | 5, // bDescriptorType = Endpoint 92 | 0x81, // bEndpointAddress = 1 IN 93 | 3, // bmAttributes = Interrupt 94 | 0x08, 0x00, // wMaxPacketSize 95 | 0xC8 // bInterval (ms) 96 | }; 97 | 98 | static const uint8_t HID_Descriptor[] = { // i am me 99 | 33, 100 | 0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop) 101 | 0x09, 0x01, // USAGE (Vendor Usage 1) 102 | 0xa1, 0x01, // COLLECTION (Application) 103 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 104 | 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 105 | 0x75, 0x08, // REPORT_SIZE (8) 106 | 107 | 0x85, 0x01, // REPORT_ID (1) 108 | 0x95, 0x06, // REPORT_COUNT (6) 109 | 0x09, 0x00, // USAGE (Undefined) 110 | 0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf) 111 | 112 | 0x85, 0x02, // REPORT_ID (2) 113 | 0x95, 0x04, // REPORT_COUNT (4) 114 | 0x09, 0x00, // USAGE (Undefined) 115 | 0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf) 116 | 0xc0 // END_COLLECTION 117 | }; 118 | 119 | // The first string descriptor (index 0) specifies the language(s) 120 | static const uint8_t String_Descriptor_0[] = { 121 | 4, // Length 122 | 4, // bLength 123 | 3, // bDescriptorType = String 124 | 0x09, 0x04 // wLangID = 0x0409 US English 125 | }; 126 | 127 | // Strings are Unicode UTF-16 128 | static const uint8_t String_Descriptor_1[] = { 129 | 20, 20, 3, 's', 0, 'i', 0, 'm', 0, 'p', 0, 'l', 0, 'e', 0, 'a', 0, 'v', 0, 'r', 0 130 | }; 131 | 132 | static const uint8_t String_Descriptor_2[] = { 133 | 16, 16, 3, 'b', 0, 'o', 0, 'o', 0, 't', 0, '4', 0, '3', 0, '0', 0, 134 | }; 135 | 136 | #define BOOT430_VER 0 137 | #define BOOT430_REL 91 138 | 139 | static uint8_t ClassReport[] = { 140 | 7, 141 | 1, /* report ID */ 142 | BOOT430_VER, 143 | BOOT430_REL, 144 | 0xff, 145 | 0xff, 146 | 0xff, 147 | 0xff, }; 148 | 149 | 150 | const uint8_t* ProtocolSetupPacket(uint8_t *pkt) 151 | { // 152 | 153 | if(pkt[2] & 0x20) { // Class Requests. 154 | switch(pkt[3]) { // 155 | case 0x01: // Get Report 156 | ClassReport[4] = *((uint8_t *) 0xff80); 157 | ClassReport[5] = *((uint8_t *) 0xff81); 158 | ClassReport[6] = *((uint8_t *) 0x0ff1); 159 | ClassReport[7] = *((uint8_t *) 0x0ff0); 160 | return ClassReport; 161 | case 0x09: // Set Report 162 | case 0x0A: // Set Idle 163 | return StatusEmpty; // 164 | } // 165 | } else { // 166 | switch(pkt[3]) { // 167 | case 0x00: // Get Status 168 | return StatusZeroZero; // 169 | case 0x05: // Set Address 170 | NewAddress = pkt[4]; // 171 | return StatusEmpty; /// This should work, but isn't reliable! 172 | case 0x06: // Get Descriptor. 173 | switch(pkt[5]) { // Which one ? 174 | case 0x01: // Device Descriptor. 175 | return Device_Descriptor; 176 | case 0x02: // Configuration Descriptor. 177 | if(pkt[8] == 9) { // 0B C3 80 06 00 02 00 00 --> 09 <-- 00 AE 04 178 | // Short Configuration Descriptor, only the first nine bytes 179 | return Configuration_Descriptor_first9; 180 | } else { // Complete Configuration Descriptor 181 | return Configuration_Descriptor_complete; 182 | } // 183 | case 0x03: // Strings 184 | switch(pkt[4]) { 185 | case 0: // 186 | return String_Descriptor_0; 187 | case 1: // 188 | return String_Descriptor_1; 189 | case 2: // 190 | return String_Descriptor_2; 191 | } // 192 | case 0x22: // HID Descriptor 193 | return HID_Descriptor; 194 | } // 195 | case 0x09: // Set Configuration 196 | return StatusEmpty; // 197 | case 0x0B: // Set Interface 198 | ReadyForTransmitIrqIn = 0; 199 | Data_PID_ToggleIrqIn = USB_PID_DATA1; 200 | return StatusEmpty; // 201 | } // 202 | } // 203 | return 0; // 204 | } // 205 | 206 | 207 | volatile uint8_t keyCnt=4; 208 | 209 | void IrqIn(uint8_t *d) { 210 | *d++ = 3; 211 | *d++ = (Data_PID_ToggleIrqIn ^= (USB_PID_DATA0 ^ USB_PID_DATA1)); 212 | 213 | *d++ = 0; 214 | *d = 0; 215 | } 216 | -------------------------------------------------------------------------------- /bbusb_protocol_hid.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2012 Kevin Timmerman 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | // 17 | #include 18 | #include "bbusb.h" 19 | 20 | 21 | extern const uint8_t *ReadyForTransmit; 22 | extern unsigned NewAddress; 23 | extern uint8_t *ReadyForTransmitIrqIn; 24 | extern unsigned Data_PID_ToggleIrqIn; 25 | 26 | 27 | static const uint8_t StatusEmpty[] = { 28 | 0 29 | }; 30 | 31 | static const uint8_t StatusZeroZero[] = { 32 | 2, 0, 0 33 | }; 34 | 35 | static const uint8_t Device_Descriptor[] = { // Mouse Device Descriptor 36 | 18, // Length 37 | 0x12, // bLength 38 | 0x01, // bDescriptorType = Device 39 | 0x10, 0x01, // bcdUSB (USB Spec Rev 1.10) 40 | 0x00, // bDeviceClass 41 | 0x00, // bDeviceSubClass 42 | 0x00, // bDeviceProtocol 43 | 0x08, // bMaxPacketSize0 44 | 0x34, 0x12, // idVendor 45 | 0x01, 0x00, // idProduct 46 | 0x01, 0x00, // bcdDevice 47 | 0x01, // iManufactuer (String descriptor index) 48 | 0x02, // iProduct (String descriptor index) 49 | 0x00, // iSerialNumber (String descriptor index) 50 | 0x01 // idNumConfigurations 51 | }; 52 | 53 | static const uint8_t Configuration_Descriptor_first9[] = { 54 | 9, 9, 2, 34, 0, 1, 1, 0, 0x80, 50 55 | }; 56 | 57 | static const uint8_t Configuration_Descriptor_complete[] = { 58 | 34, // Length 59 | // - Config Descriptor 60 | 9, // bLength 61 | 2, // bDescriptorType = Configuration 62 | 34, 0, // wTotalLength 63 | 1, // bNumInterfaces 64 | 1, // bConfigurationValue (Used by Set Configuration request) 65 | 0, // iConfiguration (String descriptor for this configuration) 66 | 0x80, // bmAttributes 67 | 50, // bMaxPower (in units of 2 mA) 68 | // - Interface Descriptor 69 | 9, // bLength 70 | 4, // bDescriptorType = Interface 71 | 0, // bInterfaceNumber 72 | 0, // bAlternateSetting 73 | 1, // bNumEndpoints 74 | 3, // bInterfaceClass = HID 75 | 1, // bInterfaceSubClass = Boot 76 | 2, // bInterfaceProtocol = Mouse 77 | 0, // iInterface (String descriptor for this interface) 78 | // - HID Descriptor 79 | 9, // bLength 80 | 0x21, // bDescriptorType = HID 81 | 0x10, 0x01, // bcdHID (Class Spec Version 1.10) 82 | 0, // bCountryCode 83 | 1, // bNumDescriptors 84 | 34, // bDescriptorType = Report 85 | 52, 0, // wDescriptorLength 86 | // - Endpoint Descriptor 87 | 7, // bLength 88 | 5, // bDescriptorType = Endpoint 89 | 0x81, // bEndpointAddress = 1 IN 90 | 3, // bmAttributes = Interrupt 91 | 0x05, 0x00, // wMaxPacketSize 92 | 0x0A // bInterval (ms) 93 | }; 94 | 95 | static const uint8_t HID_Descriptor[] = { // Mouse HID Descriptor - 3 buttons + wheel 96 | 52, // Length 97 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 98 | 0x09, 0x02, // USAGE (Mouse) 99 | 0xA1, 0x01, // COLLECTION (Application) 100 | 0x09, 0x01, // USAGE (Pointer) 101 | 0xA1, 0x00, // COLLECTION (Physical) 102 | 0x05, 0x09, // USAGE_PAGE (Button) 103 | 0x19, 0x01, // USAGE_MINIMUM (Button 1) 104 | 0x29, 0x03, // USAGE_MAXIMUM (Button 3) 105 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 106 | 0x25, 0x01, // LOGICAL_MAXIMUM (1) 107 | 0x95, 0x03, // REPORT_COUNT (3) L/M/R Buttons 108 | 0x75, 0x01, // REPORT_SIZE (1) 109 | 0x81, 0x02, // INPUT (Data,Var,Abs) 110 | 0x95, 0x01, // REPORT_COUNT (1) 111 | 0x75, 0x05, // REPORT_SIZE (5) 5 bits padding after buttons 112 | 0x81, 0x03, // INPUT (Cnst,Var,Abs) 113 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 114 | 0x09, 0x30, // USAGE (X) X rel postion 115 | 0x09, 0x31, // USAGE (Y) Y rel position 116 | 0x09, 0x38, // USAGE (Wheel) Wheel rel position 117 | 0x15, 0x81, // LOGICAL_MINIMUM (-127) 118 | 0x25, 0x7F, // LOGICAL_MAXIMUM (127) 119 | 0x95, 0x03, // REPORT_COUNT (3) 120 | 0x75, 0x08, // REPORT_SIZE (8) 121 | 0x81, 0x06, // INPUT (Data,Var,Rel) 122 | 0xC0, // END_COLLECTION 123 | 0xC0 // END_COLLECTION 124 | }; 125 | 126 | // The first string descriptor (index 0) specifies the language(s) 127 | static const uint8_t String_Descriptor_0[] = { 128 | 4, // Length 129 | 4, // bLength 130 | 3, // bDescriptorType = String 131 | 0x09, 0x04 // wLangID = 0x0409 US English 132 | }; 133 | 134 | // Strings are Unicode UTF-16 135 | static const uint8_t String_Descriptor_1[] = { 136 | 16, 16, 3, 'o', 0, 'P', 0, 'o', 0, 's', 0, 's', 0, 'u', 0, 'm', 0 137 | }; 138 | 139 | #ifdef USE_32768HZ_XTAL 140 | static const uint8_t String_Descriptor_2[] = { 141 | 30, 30, 3, 'M', 0, 'o', 0, 'u', 0, 's', 0, 'e', 0, ' ', 0, '4', 0, '3', 0, '0', 0 142 | , ' ', 0, 'X', 0, 'T', 0, 'A', 0, 'L', 0 143 | }; 144 | #else 145 | static const uint8_t String_Descriptor_2[] = { 146 | 20, 20, 3, 'M', 0, 'o', 0, 'u', 0, 's', 0, 'e', 0, ' ', 0, '4', 0, '3', 0, '0', 0 147 | }; 148 | #endif 149 | 150 | const uint8_t* ProtocolSetupPacket(uint8_t *pkt) 151 | { // 152 | if(pkt[2] & 0x20) { // Class Requests. 153 | switch(pkt[3]) { // 154 | case 0x0A: // Set Idle 155 | return StatusEmpty; // 156 | } // 157 | } else { // 158 | switch(pkt[3]) { // 159 | case 0x00: // Get Status 160 | return StatusZeroZero; // 161 | case 0x05: // Set Address 162 | NewAddress = pkt[4]; // 163 | return StatusEmpty; /// This should work, but isn't reliable! 164 | case 0x06: // Get Descriptor. 165 | switch(pkt[5]) { // Which one ? 166 | case 0x01: // Device Descriptor. 167 | return Device_Descriptor; 168 | case 0x02: // Configuration Descriptor. 169 | if(pkt[8] == 9) { // 0B C3 80 06 00 02 00 00 --> 09 <-- 00 AE 04 170 | // Short Configuration Descriptor, only the first nine bytes 171 | return Configuration_Descriptor_first9; 172 | } else { // Complete Configuration Descriptor 173 | return Configuration_Descriptor_complete; 174 | } // 175 | case 0x03: // Strings 176 | switch(pkt[4]) { 177 | case 0: // 178 | return String_Descriptor_0; 179 | case 1: // 180 | return String_Descriptor_1; 181 | case 2: // 182 | return String_Descriptor_2; 183 | } // 184 | case 0x22: // HID Descriptor 185 | return HID_Descriptor; 186 | } // 187 | case 0x09: // Set Configuration 188 | return StatusEmpty; // 189 | case 0x0B: // Set Interface 190 | ReadyForTransmitIrqIn = 0; 191 | Data_PID_ToggleIrqIn = USB_PID_DATA1; 192 | return StatusEmpty; // 193 | } // 194 | } // 195 | return 0; // 196 | } // 197 | // 198 | 199 | void IrqIn(uint8_t *d) // 200 | { // -- Mouse HID response 201 | *d++ = 5; // Length 202 | // Data PID toggle 203 | *d++ = (Data_PID_ToggleIrqIn ^= (USB_PID_DATA0 ^ USB_PID_DATA1)); 204 | *d++ = 0; // Buttons 205 | *d++ = 1; // X 206 | *d++ = 0; // Y 207 | *d++ = 0; // Wheel 208 | } // 209 | -------------------------------------------------------------------------------- /bbusb_receive.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bbusb.inc" 3 | 4 | ; 5 | ; Mecrimus-B - A firmware-only USB implementation for MSP430 microcontrollers 6 | ; Copyright (C) 2012 Matthias Koch 7 | ; 8 | ; This program is free software: you can redistribute it and/or modify 9 | ; it under the terms of the GNU General Public License as published by 10 | ; the Free Software Foundation, either version 3 of the License, or 11 | ; (at your option) any later version. 12 | ; 13 | ; This program is distributed in the hope that it will be useful, 14 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | ; GNU General Public License for more details. 17 | ; 18 | ; You should have received a copy of the GNU General Public License 19 | ; along with this program. If not, see . 20 | ; 21 | ; Ported to CCS v4 by Kevin Timmerman 2012.12 22 | ; Ported to mspgcc by Chris Chung 2012.12 23 | ; . added check upon interrupt entry to decide if bootloader or application get interrupt 24 | ; 25 | ; Receiver for 15 MHz, 10 cycles/bit 26 | ; 27 | ; 28 | .section .text ; 29 | ; 30 | .word CurrentAddress ; 31 | .word NewAddress ; 32 | .word ReadyForTransmit ; 33 | .word ReadyForTransmitIrqIn ; 34 | .word DataPacketBuffer ; 35 | .word ReceiveBufferPointer ; 36 | .word TokenPacketBuffer ; 37 | ; 38 | .word USB_Transmit ; 39 | ;.word USB_Transmit_CRC ; 40 | ; 41 | ; 42 | .if CRC_STYLE ; 43 | usb_packet_ack: ; 44 | .byte 1, USB_PID_ACK ; 45 | usb_packet_nak: ; 46 | .byte 1, USB_PID_NAK ; 47 | usb_packet_stall: ; 48 | .byte 1, USB_PID_STALL ; 49 | .endif ; 50 | ; 51 | ; 52 | .macro nrzi_r10 ; 53 | mov.b @r9, r10 ; [1] NRZI 54 | ; [2] <--- Sampling 55 | xor r10, r11 ; [3] 56 | and #usbminus, r11 ; [4] 57 | rrc.b r12 ; [5] 58 | .endm ; 59 | ; 60 | .macro nrzi_r11 ; 61 | mov.b @r9, r11 ; [1] NRZI 62 | ; [2] <--- Sampling 63 | xor r11, r10 ; [3] 64 | and #usbminus, r10 ; [4] 65 | rrc.b r12 ; [5] 66 | .endm ; 67 | ; 68 | ; 69 | .macro xnstuff register, bitmask ; (this macro was unstuff, now retired) 70 | bit r8, r12 ; [8] Detect stuffing, 6 bits without change... 71 | 1: jnz 1f ; [9] Data bits inverted here ! 72 | ; [10] 73 | mov.b @r9, \register ; [e 1] 74 | ; [e 2] <--- Read state again for proper NRZI decoding 75 | bis #0x80, r12 ; [e 3] Set MSB in data 76 | ; [e 4] 77 | xor #\bitmask, r13 ; [e 5] Set changed place in bitstuff mask 78 | ; 79 | ; Insert one nop more if constant generator can be used 80 | .if (bitmask == 1) | ( bitmask == 2 ) | ( bitmask == 4 ) | (bitmask == 8) 81 | nop ; [ e 6 ] 82 | .endif ; 83 | jmp 1b ; [e 7 - e 8] 84 | 1: ; Finished stuffing 85 | .endm ; 86 | ; 87 | .macro unstuff register, bitmask ; 88 | bit r8, r12 ; [8] Detect stuffing, 6 bits without change... 89 | 1: jnz 1f ; [9] Data bits inverted here ! 90 | ; [10] 91 | mov.b @r9, \register ; [e 1] 92 | ; [e 2] <--- Read state again for proper NRZI decoding 93 | and #usbplus+usbminus, \register; [e 3] SE0 check 94 | ; [e 4] 95 | jz usb_se0 ; [e 5] 96 | ; [e 6] 97 | bis #0x80, r12 ; [e 7] Set MSB in data 98 | ; [e 8] 99 | xor #\bitmask, r13 ; [e 9] Set changed place in bitstuff mask 100 | ; Insert one nop more if constant generator can be used 101 | .if (bitmask == 1) | ( bitmask == 2 ) | ( bitmask == 4 ) | (bitmask == 8) 102 | nop ; [e10] 103 | .endif ; 104 | 1: ; Finished stuffing 105 | .endm ; 106 | ; 107 | ; 108 | .macro unstuff_hurry_up bitmask ; Only for 1, 2, 4, 8 because of Constant Generator use 109 | jnz 1f ; [3 not previous bit] ; Refers to the last bit unstuffing ! 110 | ; [4 not previous bit] 111 | mov r10, r11 ; [es 5] R10 in the destuff bit spin state. Put it as a basis for ready the last measurement. 112 | nop ; [es 6] 113 | bis #0x80, r12 ; [es 7] The primary bit in data 114 | ; [es 8] 115 | xor #\bitmask, r13 ; [es 9] Appropriate place for the previous bit 116 | nop ; [es 10] Remember in Stopfmaske 117 | mov.b @r9, r10 ; [es 1] R10 in the destuff bit had cashed. It must be replaced. 118 | ; [es 2] <--- Sampling ! 119 | nop2 ; [es 3] 120 | ; [es 4] Because of this detects for unstuffing in the LAST bit, we have to juggle around registers here. 121 | 1: ; Finished stuffing 122 | .endm ; 123 | ; 124 | ; Signal for Sync pattern 125 | ; Signal: 126 | ; D-: normally high, Sync: 01 01 01 00 127 | ; D+: low 10 10 10 11 128 | ; Idea: Search 1-->0 transtition, sample it precisely and look if double zero follows, else repeat. 129 | ; As initialisation after IRQ (after bit.b for zero) needs some time, we will normally not see the first zero here. 130 | ; 131 | ; --- .include "Sync-15MHz.asm" 132 | ; 133 | ; Synchronize to the pattern 01010100 on D- with 15 MHz 134 | ; Entry point for Interrupt 135 | ; 136 | .if 0 ; Prototype without timeout for counting cycles 137 | ; 138 | ; bit.b - affects flags, but does not change the register contents. 139 | ; As and.b -> If D is high, is the right jnz jump. 140 | ; 141 | ; ----------------------- ; Wait until the low state is here: 142 | - bit.b @r9, r10 ; 143 | ; <-- Sampling ; ( 9L 10L 11L 12L ) 144 | jnz - ; ( 10L 11L 12L 1H ) 145 | ; ; ( 11L 12L 1H 2H ) 146 | ; ----------------------- ; Low detected. Wait till high state because: 147 | - bit.b @r9, r11 ; ( 12L 1H 2H 3H ) 148 | ; <-- Sampling ; ( 1H 2H 3H 4H ) 149 | jz - ; ( 2H 3H 4H 5H ) 150 | ; ; ( 3H 4H 5H 6H ) 151 | ; ----------------------- ; Now there is high. 152 | ; 153 | .endif ; 154 | ; 155 | ; Enter with interrupt triggered by low-to-high-transtion on D+ 156 | ; This is required to not trigger syncing on Keep-Alive-SE0s. 157 | ; 158 | ; Idea: Each bit is 10 bars long in the line 159 | ; Sync to the pattern 01010100 on D- 160 | ; --------------------------------------------------------------------------- 161 | ; 162 | Usb_Sync_Error_9_10_11_12: ; 163 | pop r12 ; 164 | pop r11 ; 165 | Usb_Sync_Error_9_10: ; Error happened 166 | pop r10 ; 167 | pop r9 ; 168 | bic.b #usbplus, &usbifg ; Clear interrupt pending bit to prevent an endless loop in case of false sync or Reset. 169 | reti ; 170 | ; 171 | ; 172 | ; --------------------------------------------------------------------------- 173 | .global __isr_2 174 | __isr_2: 175 | #ifndef USE_32768HZ_XTAL 176 | cmp.b #15, &BCSCTL1 ; Real Entry point of interrupt 177 | jz USB_Sync ; if I am running at 15Mhz, I am bootloader 178 | br &0xffa4 ; no, jump to application interrupt handler 179 | #else 180 | ;#error @simpleavr @M-atthias For the moment, detecting whether we are in bootloader or not with a crystal is not implemented. 181 | #endif 182 | 183 | USB_Sync: ; Entry point of interrupt 184 | push r9 ; 185 | push r10 ; 186 | ; 187 | USB_Quick_Resync: ; 188 | mov #usbin, r9 ; 189 | mov #usbminus, r10 ; 190 | ; 191 | ;bit.b @r9, r10 ; Waiting for a low in D 192 | ; <-- Sampling ; 1 193 | ;jz j00 ; 2 194 | ; ; 3 195 | bit.b @r9, r10 ; 4 196 | ; <-- Sampling ; 5 Waiting to NULL in D 197 | jz j00 ; 6 Wait for Low in D- 198 | ; ; 7 199 | bit.b @r9, r10 ; 8 200 | ; <-- Sampling ; 9 201 | jz j00 ; 10 202 | ; ; 11 203 | bit.b @r9, r10 ; 12 204 | ; <-- Sampling ; 13 205 | jnz Usb_Sync_Error_9_10 ; 206 | ; ; 207 | j00:; ----------------------- ; Low detected 208 | bit.b @r9, r10 ; 209 | ; <-- Sampling ; 1 210 | jnz j01 ; 2 211 | ; ; 3 212 | bit.b @r9, r10 ; 4 213 | ; <-- Sampling ; 5 Waiting for ONE in D 214 | jnz j01 ; 6 Wait for High in D- 215 | ; ; 7 216 | bit.b @r9, r10 ; 8 217 | ; <-- Sampling ; 9 218 | jnz j01 ; 10 219 | ; ; 11 220 | bit.b @r9, r10 ; 12 221 | ; <-- Sampling ; 13 222 | jz Usb_Sync_Error_9_10 ; 223 | ; ; High detected, synced within 4 cycles 224 | j01:; ------------> ; ( 3H 4H 5H 6H ) Leave the preliminary sync with these bars 225 | ; ----------------------- ; First try to sync precisely 226 | push r11 ; ( 4H 5H 6H 7H ) 227 | ; ; ( 5H 6H 7H 8H ) 228 | ; ; ( 6H 7H 8H 9H ) 229 | mov.b @r9, r10 ; ( 7H 8H 9H 10H ) 230 | ; <-- Sampling ; ( 8H 9H 10H 1L ) 231 | mov.b @r9, r11 ; ( 9H 10H 1L 2L ) 232 | ; <-- Sampling ; ( 10H 1L 2L 3L ) 233 | ; ----------------- ; ( | | | | ) 234 | bit #usbminus, r10 ; ( 1L 2L 3L 4L ) 235 | jnc j02 ; ( 2L 3L 4L 5L ) 236 | ; ; ( 3L 4L 5L 6L ) 237 | bit #usbminus, r11 ; ( 4L 5L 6L | ) 238 | jnc j03 ; ( 5L 6L 7L | ) 239 | ; ; ( 6L 7L 8L | ) 240 | j02: nop2 ; ( 7L | | 7L ) 241 | ; ; ( 8L | | 8L ) 242 | j03:; ----------------- ; ( ) Edge sampling finished 243 | push r12 ; ( 9L 8L 9L 9L ) 244 | ; ; ( 9L 10L ) 245 | ; ; ( 10L 1N ) 246 | nop ; ( 1N 2N ) 247 | mov.b @r9, r10 ; ( 2N 3N ) Check, if this is really low for two bit times 248 | ; <-- Sampling ; ( 3N 4N ) 249 | bit #usbminus, r10 ; ( 4N 5N ) 250 | jnc Usb_Rec_Einlauf ; ( 5N 6N ) 251 | ; ; ( 6N 7N ) 252 | ; 253 | ; ----------------------- ; Second try to sync precisely 254 | nop2 ; ( 5H 6H 7H 8H ) Another syncinc run with entry on 7/8 leads to sync with one cycle accuracy. 255 | ; ; ( 6H 7H 8H 9H ) 256 | mov.b @r9, r10 ; ( 7H 8H 9H 10H ) 257 | ; <-- Sampling ; ( 8H 9H 10H 1L ) 258 | mov.b @r9, r11 ; ( 9H 10H 1L 2L ) 259 | ; <-- Sampling ; ( 10H 1L 2L 3L ) 260 | ; ----------------- ; ( | | | | ) 261 | bit #usbminus, r10 ; ( 1L 2L 3L 4L ) 262 | jnc j04 ; ( 2L 3L 4L 5L ) 263 | ; ; ( 3L 4L 5L 6L ) 264 | bit #usbminus, r11 ; ( 4L 5L 6L | ) 265 | jnc j05 ; ( 5L 6L 7L | ) 266 | ; ; ( 6L 7L 8L | ) 267 | j04: nop2 ; ( 7L | | 7L ) 268 | ; ; ( 8L | | 8L ) 269 | j05:; ----------------- ; ( ) Edge sampling finished 270 | nop2 ; ( 9L 8L 9L 9L ) 271 | ; ; ( 9L 10L ) 272 | nop2 ; ( 10L 1N ) 273 | ; ; ( 1N 2N ) 274 | mov.b @r9, r10 ; ( 2N 3N ) Check, if this is really low for two bit times 275 | ; <-- Sampling ; ( 3N 4N ) 276 | bit #usbminus, r10 ; ( 4N 5N ) 277 | jnc Usb_Rec_Einlauf ; ( 5N 6N ) 278 | ; ; ( 6N 7N ) 279 | ; 280 | ; ----------------------- ; Third and last try to sync precisely 281 | nop2 ; ( 5H 6H 7H 8H ) Another syncinc run with entry on 7/8 leads to sync with one cycle accuracy. 282 | ; ; ( 6H 7H 8H 9H ) 283 | mov.b @r9, r10 ; ( 7H 8H 9H 10H ) 284 | ; <-- Sampling ; ( 8H 9H 10H 1L ) 285 | mov.b @r9, r11 ; ( 9H 10H 1L 2L ) 286 | ; <-- Sampling ; ( 10H 1L 2L 3L ) 287 | ; ----------------- ; ( | | | | ) 288 | bit #usbminus, r10 ; ( 1L 2L 3L 4L ) 289 | jnc j06 ; ( 2L 3L 4L 5L ) 290 | ; ; ( 3L 4L 5L 6L ) 291 | bit #usbminus, r11 ; ( 4L 5L 6L | ) 292 | jnc j07 ; ( 5L 6L 7L | ) 293 | ; ; ( 6L 7L 8L | ) 294 | j06: nop2 ; ( 7L | | 7L ) 295 | ; ; ( 8L | | 8L ) 296 | j07:; ----------------- ; ( ) Edge sampling finished 297 | nop2 ; ( 9L 8L 9L 9L ) 298 | ; ; ( 9L 10L ) 299 | nop2 ; ( 10L 1N ) 300 | ; ; ( 1N 2N ) 301 | mov.b @r9, r10 ; ( 2N 3N ) Check, if this is really low for two bit times 302 | ; <-- Sampling ; ( 3N 4N ) 303 | bit #usbminus, r10 ; ( 4N 5N ) 304 | ; ( 5N 6N ) 305 | jc Usb_Sync_Error_9_10_11_12 ; 306 | ; ; ( 6N 7N ) 307 | ; 308 | Usb_Rec_Einlauf: ; 309 | nop2 ; ( 7N 8N ) Sync is finished. Prepare to run into receiver ! 310 | ; ; ( 8N 9N ) 311 | toggle_syncled ; ( 9N 10N ) 312 | ; ; ( 10N 1B ) 313 | ; ; ( 1B 2B ) 314 | ; <-- Wechsel ; ( 2B 3B ) Syncled is electrically toggled now. 315 | ; --------------------------------------- Entry in receiver now. 316 | ; mov.b @r9, ... ; ( 3B 4B ) 317 | ; <-- Sampling ; ( 4B 5B ) 318 | ; 319 | ; --- end .include "Sync-15MHz.asm" 320 | ; 321 | ; --------------------------------------------------------------------------- 322 | ; Sync is ok, lets start ! 323 | ; 324 | ; Can do preparations while running in, because there cannot occour stuffing on the first few bits. 325 | ; 326 | ; Register usage: 327 | ; r8 ; Mask for detect stuffing 328 | ; r9 ; Address of P2IN 329 | ; 330 | ; r10 ; Buffer for NRZI pin state 331 | ; r11 ; -- 332 | ; 333 | ; r12 ; Data input shift register, has to be initialized to sync-pattern not(9f0) 334 | ; r13 ; Stuffing mask, has to be cleared 335 | ; 336 | ; r14 ; Data backup register 337 | ; r15 ; Pointer to write into receive buffer 338 | ; 339 | ; Note: Data is inverted because of clever use of flags and side-effects to save cycles 340 | ; Stuffing mask holds those bits that have been inverted, so that stuffing detection 341 | ; will not detect stuffing on the same bits more than one time. 342 | ; 343 | ; We have some time in the first byte of data, as stuffing cannot occour the first 5 bits. 344 | ; D- is used for sync and input, D+ is only used to detect packet end SE0. 345 | ; 346 | ; --------------------------------------------------------------------------- 347 | ; First Bit: (0) Run-in with preparations 348 | ; --------------------------------------------------------------------------- 349 | ; 350 | mov.b @r9, r10 ; [1] NRZI ( 3 4) Chance counting here so that mov.b @r9 always counts on one. 351 | ; [2] <--- Sampling ( 4 5) Center-Sampling on 5 or 6 ! 352 | mov #0x7F, r12 ; [3] not(9f0) ( 5 6) Initialize data, as last bit of Syncpattern may take part in stuffing. 353 | ; [4] 354 | and #usbminus, r10 ; [5] instead bit Wechsele initiate here the method of payment! One arrogated deliver directly the value of the first bit. Depends on sync byte final. There is D-low. Exchange - set> Carry. Get there :-) 355 | rrc.b r12 ; [6] and rotate the MOV instruction comes as ever on record [1] :-) First Data bit! Usbminus contains the first data bit inverted. fits :-) 356 | ; Catch first data bit, use only AND here, as last state out of sync pattern is always the same. 357 | push r13 ; [7] Save more registers 358 | ; [8] 359 | ; [9] 360 | clr r13 ; [10] Clear stuffing mask 361 | ; 362 | ; --------------------------------------------------------------------------- 363 | ; Second Bit: (1) Run-in with preparations 364 | ; --------------------------------------------------------------------------- 365 | ; 366 | nrzi_r11 ; [1-5] 367 | push r14 ; [6] The data backup register doesn't need initialisation. 368 | ; [7] 369 | ; [8] 370 | ; [9] Fetch the Pointer in two steps, could be in one step @ 18 MHz/12 cycles. 371 | mov #ReceiveBufferPointer, r14 ; 372 | ; [10] 373 | ; 374 | ; --------------------------------------------------------------------------- 375 | ; Third Bit: (2) Run-in with preparations 376 | ; --------------------------------------------------------------------------- 377 | nrzi_r10 ; [1-5] 378 | push r15 ; [6] Pointer to write reveived data, has to be initialized. 379 | ; [7] 380 | ; [8] 381 | mov @r14, r15 ; [9] Second step of fetching buffer pointer 382 | ; [10] 383 | ; 384 | ; --------------------------------------------------------------------------- 385 | ; Fourth Bit: (3) Run-in with preparations 386 | ; --------------------------------------------------------------------------- 387 | nrzi_r11 ; [1-5] 388 | push r8 ; [6] Stopfmaskenregister secure 389 | ; [7] 390 | ; [8] 391 | mov #0xfc, r8 ; [9] Prepare mask to quickly detect last 6 bits for stuffing 392 | ; [10] 393 | ; 394 | ; --------------------------------------------------------------------------- 395 | ; Fifth Bit: (4) Skip into regulare scheme 396 | ; --------------------------------------------------------------------------- 397 | nrzi_r10 ; [1-5] 398 | ; [6-7] Jump into regular cycle 399 | jmp Mittendrin_im_fuenften_Bit ; 400 | ; 401 | ; 402 | USB_ReceiverLoop: ; 403 | ; --------------------------------------------------------------------------- 404 | ; First Bit: (0) Special task: Clear stuffmask, invert data 405 | ; --------------------------------------------------------------------------- 406 | nrzi_r10 ; [1-5] 407 | clr r13 ; [8] Clear stuffing mask. Relevant information is still in r12 and gets shifted out by the way. 408 | inv r14 ; [9] Invert saved data byte. 409 | unstuff r10, 1 ; [8-10] 410 | ; 411 | ; --------------------------------------------------------------------------- 412 | ; Second Bit: (1) Special task: Detect SE0 413 | ; --------------------------------------------------------------------------- 414 | mov.b @r9, r11 ; [1] NRZI einleiten mit Sampling 415 | ; [2] <--- Sampling 416 | ; [s3] Check for SE0 417 | and #usbplus+usbminus, r11 ; 418 | ; [s4] 419 | jz usb_se0 ; [s5] Which occours as low low in both USB lines 420 | ; [s6] Unfortunately this takes whole 4 cycles... 421 | xor r11, r10 ; [7] 422 | and #usbminus, r10 ; [8] NRZI go through 423 | rrc.b r12 ; [9] 424 | bit r8, r12 ; [10] Stopferkennung, 6 bits in succession, no change! 425 | ; 426 | ; --------------------------------------------------------------------------- 427 | ; Third Bit: (2) Special task: Hurry up ! 428 | ; --------------------------------------------------------------------------- 429 | mov.b @r9, r10 ; [1] NRZI to initiate sampling 430 | ; [2] <--- Sampling flags are retained! 431 | unstuff_hurry_up 2 ; [3-4] 432 | xor r10, r11 ; [5] 433 | and #usbminus, r11 ; [6] NRZI 2 Clocks go through later. New sampling in unclogging! 434 | rrc.b r12 ; [7] 435 | unstuff r10, 4 ; [8-10] 436 | ; 437 | ; --------------------------------------------------------------------------- 438 | ; Fourth Bit: (3) Special task: Write data into buffer 439 | ; --------------------------------------------------------------------------- 440 | nrzi_r11 ; [1-5] 441 | mov.b r14, 0(r15) ; [p6] and put freshly prepared data into. 442 | ; [p7] 443 | ; [p8] 444 | ; [p9] 445 | bit r8, r12 ; [10] Stopferkennung, 6 bits in succession, no change! 446 | ; 447 | ; --------------------------------------------------------------------------- 448 | ; Fifth Bit: (4) Special task: Hurry up ! 449 | ; --------------------------------------------------------------------------- 450 | mov.b @r9, r10 ; [1] NRZI Initiate with sampling 451 | ; [2] <--- Sampling flags are retained! 452 | unstuff_hurry_up 8 ; [3-4] 453 | xor r10, r11 ; [5] 454 | and #usbminus, r11 ; [6] NRZI 2 Bars later perform. New sampling in unclogging! 455 | rrc.b r12 ; [7] 456 | Mittendrin_im_fuenften_Bit: ; 457 | unstuff r10, 16 ; [8-10] 458 | ; 459 | ; --------------------------------------------------------------------------- 460 | ; Sixth Bit: (5) Pointer further Racken 461 | ; --------------------------------------------------------------------------- 462 | nrzi_r11 ; [1-5] 463 | inc r15 ; [6] 464 | nop ; [7] 465 | unstuff r11, 32 ; [8-10] 466 | ; 467 | ; --------------------------------------------------------------------------- 468 | ; Seventh Bit: (6) Free of special tasks 469 | ; --------------------------------------------------------------------------- 470 | nrzi_r10 ; [1-5] 471 | nop2 ; [6-7] 472 | unstuff r10, 64 ; [8-10] 473 | ; 474 | ; --------------------------------------------------------------------------- 475 | ; Eigth Bit: (7) Special task: Save data for later preparation and apply stuffmask. 476 | ; Jump back with stuffing-jump to save cycles ! 477 | ; --------------------------------------------------------------------------- 478 | nrzi_r11 ; [1-5] 479 | mov r12, r14 ; [6] Data byte is ready! Fetch it. Backup of Data 480 | bic r13, r14 ; [7] Apply stuffmask 481 | bit r8, r12 ; [8] Stopferkennung, 6 bits in succession, no change! 482 | jnz USB_ReceiverLoop ; [9] Return with stuff-detect-jump 483 | ; [10] 484 | ; Unstuffing for last bit. 485 | mov.b @r9, r11 ; [e 1] For the NRZI decoding change state. 486 | ; [e 2] <--- Sampling State simply read again 487 | and #usbminus, r11 ; [e 3] 488 | bis #0x80, r12 ; [e 4] The primary bit in data, data register is 16 bits wide and runs through! 489 | ; [e 5] Set MSB in data, this is rotated further later. 490 | nop ; [e 6] Do not log in Stopfmaske, 491 | nop2 ; [e 7] since this bit is pushed completely 492 | ; [e 8] and Stopfmaske is anyway deleted. 493 | jmp USB_ReceiverLoop ; [e 9] 494 | ; [e 10] In the last bit there is no need to update stuffmask, as data byte is already saved, 495 | ; but it is necessary to set the bit in data register, as stuffing continues over byte boundaries. 496 | ; It will be shifted out later anyway... 497 | ; 498 | ; --------------------------------------------------------------------------- 499 | ; SE0: End of packet detected. 500 | ; --------------------------------------------------------------------------- 501 | ; --- .include "Receiver-Common.asm" 502 | ; Frequency independent parts of receiver 503 | ; --------------------------------------------------------------------------- 504 | ; SE0: End of packet detected. 505 | ; --------------------------------------------------------------------------- 506 | usb_se0: ; Come with [7] Here! 507 | ; 508 | bic.b #usbplus, &usbifg ; Interrupt-Pending-Flag listening immediately after SE0 and after sending. 509 | ; The re-rise of SE0 to J triggers an interrupt. 510 | ; 511 | mov.b r14, 0(r15) ; [8] :-) Store last Databyte in Buffer 512 | ; [9] 513 | ;[10] 514 | ; 515 | ; [1] Fetch bufferpointer 516 | mov &ReceiveBufferPointer, r14 ; 517 | ; [2] 518 | ; [3] 519 | sub r14, r15 ; [4] Calculate length of received packet 520 | mov.b r15, 0(r14) ; [5] Store length like in a counted string 521 | ; [6] 522 | ; [7] 523 | ; 524 | toggle_syncled ; Finished. Toggle syncled again, to see on oscilloscope if SE0 detection missed its job due to wrong sync. 525 | ; 526 | ;------------------------------------------------------------------------------ 527 | mov.b 1(r14), r10 ; Fetch PID of packet for further investigation. 528 | mov.b 2(r14), r11 ; Fetch field that may contain address 529 | mov.b 3(r14), r12 ; Fetch field that may contain endpoint 530 | bit #0x080, r11 ; Fetch LSB bit of endpoint 531 | rlc r12 ; Rotate that bit in 532 | and #0x00F, r12 ; Remove CRC5 from endpoint 533 | bic #0x080, r11 ; Clear Endpoint bit in address 534 | ; 535 | cmp #USB_PID_IN, r10 ; 536 | jeq usb_in ; 537 | cmp #USB_PID_OUT, r10 ; 538 | jeq usb_out_setup ; 539 | cmp #USB_PID_SETUP, r10 ; 540 | jeq usb_out_setup ; 541 | ; Do this only if the packet was for me and the receive pointer has 542 | ; been set accordingly. 543 | cmp #DataPacketBuffer, &ReceiveBufferPointer 544 | jne usb_pop_and_finish ; 545 | ; This is for me ! Accept it. 546 | ; Switch back receive buffer 547 | mov #TokenPacketBuffer, &ReceiveBufferPointer 548 | ; 549 | cmp #USB_PID_DATA0, r10 ; 550 | jeq usb_data ; 551 | cmp #USB_PID_DATA1, r10 ; 552 | jeq usb_data ; 553 | ; 554 | usb_pop_and_finish: ; 555 | pop r8 ; 556 | pop r15 ; 557 | pop r14 ; 558 | pop r13 ; 559 | pop r12 ; 560 | pop r11 ; 561 | ; Is there already the next packet in the line ? 562 | bit.b #usbplus, &usbifg ; (Or vice versa, in order to save strokes?) 563 | jc USB_Quick_Resync ; Catch it immediately ! This entry point is only possible if r9 is not changed. 564 | ; 565 | pop r10 ; 566 | pop r9 ; 567 | ; Next packet now in line ? 568 | bit.b #usbplus, &usbifg ; Or vice versa, in order to save strokes?) 569 | jc USB_Sync ; If yes, catch it. Else handle it with another interrupt. 570 | reti ; 571 | ; 572 | ; Next paket may follow in 2 bittimes = 20 cycles. 573 | ; If I have to reply, I have 6.5 to 7.5 bittimes maximum until I have to transmit my answer. 574 | ; So I should check first if I have to receive some more... 575 | ; Note that we can take up some time of the sync pattern, as we need only the second half "0100" of it... 576 | ; 577 | ; 578 | usb_in: ; 579 | cmp.b r11, &CurrentAddress ; For me ? 580 | jne usb_pop_and_finish ; 581 | ; 582 | cmp #1, r12 ; Check endpoint ! 583 | jne j10 ; 584 | mov &ReadyForTransmitIrqIn, r15 ; Fetch pointer for outgoing packets for Irq-In endpoint 585 | clr &ReadyForTransmitIrqIn ; Buffer ready for refill 586 | jmp j11 ; 587 | ; 588 | j10: mov &ReadyForTransmit, r15 ; Fetch pointer for outgoing packets 589 | clr &ReadyForTransmit ; Buffer ready for refill 590 | ; 591 | j11: cmp #0, r15 ; Something inside ? 592 | jne j12 ; 593 | .if CRC_STYLE ; 594 | mov #usb_packet_nak, r15 ; If not, send NAK 595 | br #USB_Transmit ; 596 | .else ; 597 | mov #(USB_PID_NAK << 8) ^ 0xFF7F, R14 598 | jmp ack_nak ; 599 | .endif ; 600 | ; 601 | j12: ; 602 | ; Address changes are committed after Status Stage. Do this here ! 603 | tst 0(R15) ; Stall? 604 | jz usb_stall ; 605 | mov &NewAddress, &CurrentAddress ; 606 | br #USB_Transmit ; 607 | ; 608 | ; 609 | usb_stall: ; 610 | .if CRC_STYLE ; 611 | mov #usb_packet_stall, r15 ; Send STALL 612 | br #USB_Transmit ; 613 | .else ; 614 | mov #(USB_PID_STALL << 8) ^ 0xFF7F, R14 615 | jmp ack_nak ; 616 | .endif ; 617 | 618 | usb_out_setup: ; 619 | cmp.b r11, &CurrentAddress ; For me ? 620 | jne usb_pop_and_finish ; 621 | ; 622 | ; Save PID 623 | mov.b r10, &DataPacketBuffer + 15 ; 624 | ; Get ready to receive data with destination "me" 625 | mov #DataPacketBuffer, &ReceiveBufferPointer 626 | jmp usb_pop_and_finish ; 627 | ; 628 | usb_data: ; 629 | .if CRC_STYLE ; 630 | mov #usb_packet_ack, r15 ; 631 | br #USB_Transmit ; 632 | .else ; 633 | mov #(USB_PID_ACK << 8) ^ 0xFF7F, R14 634 | ack_nak: ; 635 | clr R15 ; 636 | br #USB_Transmit ; 637 | .endif ; 638 | 639 | .global __isr_0 640 | .global __isr_1 641 | .global __isr_3 642 | .global __isr_4 643 | .global __isr_5 644 | .global __isr_6 645 | .global __isr_7 646 | .global __isr_8 647 | #ifndef USE_32768HZ_XTAL 648 | .global __isr_9 649 | #endif 650 | .global __isr_10 651 | .global __isr_11 652 | .global __isr_12 653 | .global __isr_13 654 | .global __isr_14 655 | __isr_0: 656 | __isr_1: 657 | __isr_3: 658 | __isr_4: 659 | __isr_5: 660 | __isr_6: 661 | __isr_7: 662 | __isr_8: 663 | #ifndef USE_32768HZ_XTAL 664 | __isr_9: 665 | #endif 666 | __isr_10: 667 | __isr_11: 668 | __isr_12: 669 | __isr_13: 670 | __isr_14: 671 | 672 | common_return: 673 | reti 674 | ; 675 | .sect ".int02" ; 676 | .short USB_Sync ; 03: 0FFE4 Port 1 677 | ; 678 | .end ; 679 | -------------------------------------------------------------------------------- /bbusb_transmit.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bbusb.inc" 3 | 4 | ; 5 | ; Copyright (C) 2012 Kevin Timmerman 6 | ; 7 | ; This program is free software: you can redistribute it and/or modify 8 | ; it under the terms of the GNU General Public License as published by 9 | ; the Free Software Foundation, either version 3 of the License, or 10 | ; (at your option) any later version. 11 | ; 12 | ; This program is distributed in the hope that it will be useful, 13 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | ; GNU General Public License for more details. 16 | ; 17 | ; You should have received a copy of the GNU General Public License 18 | ; along with this program. If not, see . 19 | ; 20 | ; 21 | ; 15 MHz USB low speed transmitter with CRC 22 | ; 23 | ; USB uses NRZI endoding with bit stuffing 24 | ; Each 0 bit is sent as a toggle of the data lines 25 | ; Each 1 bit is sent as no change of the data lines 26 | ; After six 1 bits (no change), a zero bit (toggle) is inserted 27 | ; This is to provide enough clock edges for the receiver to stay in sync 28 | ; with the transmitter 29 | ; 30 | ; Ported to mspgcc by Chris Chung 2012.12 31 | ; 32 | ; 33 | .global USB_Transmit ; 34 | ; 35 | .section .text ; 36 | 37 | .if !CRC_STYLE 38 | crc_table: 39 | .word 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241 40 | .word 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440 41 | .word 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40 42 | .word 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841 43 | .word 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40 44 | .word 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41 45 | .word 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641 46 | .word 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040 47 | .word 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240 48 | .word 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441 49 | .word 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41 50 | .word 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840 51 | .word 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41 52 | .word 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40 53 | .word 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640 54 | .word 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041 55 | .word 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240 56 | .word 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441 57 | .word 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41 58 | .word 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840 59 | .word 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41 60 | .word 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40 61 | .word 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640 62 | .word 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041 63 | .word 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241 64 | .word 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440 65 | .word 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40 66 | .word 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841 67 | .word 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40 68 | .word 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41 69 | .word 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641 70 | .word 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 71 | .endif 72 | 73 | USB_Transmit: ; Transmit packet 74 | ; 75 | ; R15: Pointer to tx data 76 | ; Registers pushed on stack (pop before reti): 77 | ; R8, R15, R14, R13, R12, R11, R10, R9 78 | ; 79 | ; Register usage: 80 | ; R8: CRC table pointer 81 | ; R9: Data line toggle mask 82 | ; R10: Packet octet count 83 | ; R11: Tx data octet 84 | ; R12: Bit stuff counter 85 | ; R13: CRC data octet 86 | ; R14: CRC 87 | ; R15: Tx data pointer 88 | ; 89 | bic.b #usbplus, &usbout ; Default to J state 90 | bis.b #usbminus, &usbout ; D+ low, D- high 91 | ; 92 | mov #usbplus | usbminus, R9 ; Setup data line toggle mask 93 | bis.b R9, &usbdir ; Set USB data lines to output 94 | ; 95 | .if CRC_STYLE ; --- Data packet has CRC appended --- 96 | mov.b @R15+, R10 ; 8,9 Get packet length, inc pointer 97 | inc R10 ; 0 Inc length for sync octect 98 | mov #0x80, R11 ; 1,2 Begin with sync octect 99 | clr R12 ; 3 Clear bit stuff counter 100 | ; 101 | tx_data_loop: ; --- Data transmit loop --- 102 | ; - Bit 0 103 | rra R11 ; 4 Get a bit 104 | tx02: ; 105 | jnc tx00 ; 5,6 If zero bit... 106 | ; One bit - no data lines toggle 107 | dec R12 ; 7 Increment bit stuffing count 108 | cmp #-5, R12 ; 8,9 Check if stuffing needed 109 | jhs tx01 ; 0,1 No stuffing needed... 110 | nop ; 2 111 | jmp tx02 ; 3,4 Send stuffing bit 112 | tx00: ; Send zero bit 113 | xor.b R9, &usbout ; 7,8,9,0 Toggle data lines 114 | clr R12 ; 1 Clear stuffing count 115 | tx01: ; 116 | clr R8 ; 2 Clear bit loop toggle 117 | ; 118 | tx13: ; - Bit 1/3 119 | rra R11 ; 3 Get a bit 120 | tx12: ; 121 | nop ; 4 122 | jnc tx10 ; 5,6 If zero bit... 123 | ; One bit - no data lines toggle 124 | dec R12 ; 7 Increment bit stuffing count 125 | cmp #-5, R12 ; 8,9 Check if stuffing needed 126 | jhs tx11 ; 0,1 No stuffing needed... 127 | jmp tx12 ; 2,3 Send stuffing bit 128 | tx10: ; Send zero bit 129 | xor.b R9, &usbout ; 7,8,9,0 Toggle data lines 130 | clr R12 ; 1 Clear stuffing count 131 | tx11: ; 132 | ; - Bit 2/4 133 | rra R11 ; 2 Get a bit 134 | tx22: ; 135 | nop ; 3 136 | jnc tx20 ; 4,5 If zero bit... 137 | ; One bit - no data lines toggle 138 | dec R12 ; 6 Increment bit stuffing count 139 | cmp #-5, R12 ; 7,8 Check if stuffing needed 140 | jhs tx21 ; 9,0 No stuffing needed... 141 | jmp tx22 ; 1,2 Send stuffing bit 142 | tx20: ; Send zero bit 143 | clr R12 ; 6 Clear stuffing count 144 | xor.b R9, &usbout ; 7,8,9,0 Toggle data lines 145 | tx21: ; 146 | xor #1, R8 ; 1 Toggle loop count 147 | jnz tx13 ; 2,3 Do bits 2 & 3... 148 | ; 149 | ; 150 | .else ; --- !CRC_STYLE - Do on-the-fly CRC calculation 151 | clr R10 ; 1 Clear bit count 152 | tst R15 ; 2 Is there a pointer to a data packet? 153 | jeq txc0 ; 3,4 No, send sync + PID... 154 | ; 155 | ; --- Send sync + data + CRC --- 156 | tx_sync: ; - Send sync (0x80) 157 | nop ; 5 - 7 zero bits in this loop 158 | inc R10 ; 6 Increment bit count 159 | xor.b R9, &usbout ; 7,8,9,0 Toggle data lines 160 | cmp #7, R10 ; 1,2 Done with 7 bits? 161 | jne tx_sync ; 3,4 No... 162 | ; 163 | ; - 1 bit period without toggle 164 | mov.b @R15+, R10 ; 4,5 Get packet length, inc pointer 165 | mov.b @R15+, R11 ; 6,7 Get PID from tx packet, inc pointer 166 | clr R12 ; 0 Clear bit stuff counter 167 | mov #crc_table, R8 ; 8,9 Setup CRC table pointer 168 | clr R13 ; 1 Init first CRC data byte (PID will be ignored) 169 | mov #0xFE54, R14 ; 2,3 Init CRC - this will result in the CRC 170 | ; being 0xFFFF after the first pass - the PID is not included 171 | ; in the CRC calculation 172 | ; 173 | tx_data_loop: ; --- Data transmit loop --- 174 | ; - Bit 0 175 | rra R11 ; 4 Get a bit 176 | tx02: ; 177 | jnc tx00 ; 5,6 If zero bit... 178 | ; One bit - no data lines toggle 179 | dec R12 ; 7 Increment bit stuffing count 180 | cmp #-5, R12 ; 8,9 Check if stuffing needed 181 | jhs tx01 ; 0,1 No stuffing needed... 182 | nop ; 2 183 | jmp tx02 ; 3,4 Send stuffing bit 184 | tx00: ; Send zero bit 185 | xor.b R9, &usbout ; 7,8,9,0 Toggle data lines 186 | clr R12 ; 1 Clear stuffing count 187 | tx01: ; 188 | xor R14, R13 ; 2 Xor data octet with crc 189 | mov.b R13, R13 ; 3 Mask off MSB 190 | ; 191 | ; - Bit 1 192 | rra R11 ; 4 Get a bit 193 | tx12: ; 194 | jnc tx10 ; 5,6 If zero bit... 195 | ; One bit - no data lines toggle 196 | dec R12 ; 7 Increment bit stuffing count 197 | cmp #-5, R12 ; 8,9 Check if stuffing needed 198 | jhs tx11 ; 0,1 No stuffing needed... 199 | nop ; 2 200 | jmp tx12 ; 3,4 Send stuffing bit 201 | tx10: ; Send zero bit 202 | xor.b R9, &usbout ; 7,8,9,0 Toggle data lines 203 | clr R12 ; 1 Clear stuffing count 204 | tx11: ; 205 | swpb R14 ; 2 Shift CRC right by 8 bits 206 | ; by doing byte swap and MSB clear 207 | ; 208 | ; - Bit 2 209 | rra R11 ; 3 Get a bit 210 | tx22: ; 211 | mov.b R14, R14 ; 4 212 | jnc tx20 ; 5,6 If zero bit... 213 | ; One bit - no data lines toggle 214 | dec R12 ; 7 Increment bit stuffing count 215 | cmp #-5, R12 ; 8,9 Check if stuffing needed 216 | jhs tx21 ; 0,1 No stuffing needed... 217 | jmp tx22 ; 2,3 Send stuffing bit 218 | tx20: ; Send zero bit 219 | xor.b R9, &usbout ; 7,8,9,0 Toggle data lines 220 | clr R12 ; 1 Clear stuffing count 221 | tx21: ; 222 | rla R13 ; 2 Make pointer to CRC table entry 223 | add R8, R13 ; 3 224 | ; 225 | ; - Bit 3 226 | rra R11 ; 4 Get a bit 227 | tx32: ; 228 | jnc tx30 ; 5,6 If zero bit... 229 | ; One bit - no data lines toggle 230 | dec R12 ; 7 Increment bit stuffing count 231 | cmp #-5, R12 ; 8,9 Check if stuffing needed 232 | jhs tx31 ; 0,1 No stuffing needed... 233 | nop ; 2 234 | jmp tx32 ; 3,4 Send stuffing bit 235 | tx30: ; Send zero bit 236 | xor.b R9, &usbout ; 7,8,9,0 Toggle data lines 237 | clr R12 ; 1 Clear stuffing count 238 | tx31: ; 239 | mov @R13, R13 ; 2,3 Get CRC table entry 240 | ; 241 | ; - Bit 4 242 | rra R11 ; 4 Get a bit 243 | tx42: ; 244 | jnc tx40 ; 5,6 If zero bit... 245 | ; One bit - no data lines toggle 246 | dec R12 ; 7 Increment bit stuffing count 247 | cmp #-5, R12 ; 8,9 Check if stuffing needed 248 | jhs tx41 ; 0,1 No stuffing needed... 249 | nop ; 2 250 | jmp tx42 ; 3,4 Send stuffing bit 251 | tx40: ; Send zero bit 252 | xor.b R9, &usbout ; 7,8,9,0 Toggle data lines 253 | clr R12 ; 1 Clear stuffing count 254 | tx41: ; 255 | xor R13, R14 ; 2 Update CRC 256 | ; 257 | .endif ; 258 | ; - Bit 5 259 | rra R11 ; 3 Get a bit 260 | tx52: ; 261 | nop ; 4 262 | jnc tx50 ; 5,6 If zero bit... 263 | ; One bit - no data lines toggle 264 | dec R12 ; 7 Increment bit stuffing count 265 | cmp #-5, R12 ; 8,9 Check if stuffing needed 266 | jhs tx51 ; 0,1 No stuffing needed... 267 | jmp tx52 ; 2,3 Send stuffing bit 268 | tx50: ; Send zero bit 269 | xor.b R9, &usbout ; 7,8,9,0 Toggle data lines 270 | clr R12 ; 1 Clear stuffing count 271 | tx51: ; 272 | mov.b @R15+, R13 ; 2,3 Get next CRC data octet 273 | ; 274 | ; - Bit 6 275 | rra R11 ; 4 Get a bit 276 | tx62: ; 277 | jnc tx60 ; 5,6 If zero bit... 278 | ; One bit - no data lines toggle 279 | dec R12 ; 7 Increment bit stuffing count 280 | cmp #-5, R12 ; 8,9 Check if stuffing needed 281 | jhs tx61 ; 0,1 No stuffing needed... 282 | nop ; 2 283 | jmp tx62 ; 3,4 Send stuffing bit 284 | tx60: ; Send zero bit 285 | xor.b R9, &usbout ; 7,8,9,0 Toggle data lines 286 | clr R12 ; 1 Clear stuffing count 287 | tx61: ; 288 | ; 289 | ; - Bit 7 290 | rra R11 ; 2 Get a bit 291 | tx72: ; 292 | mov R13, R11 ; 3 Get next tx data octet 293 | jnc tx70 ; 4,5 If zero bit... 294 | ; One bit - no data lines toggle 295 | dec R12 ; 6 Increment bit stuffing count 296 | cmp #-5, R12 ; 7,8 Check if stuffing needed 297 | jhs tx71 ; 9,0 No stuffing needed... 298 | jmp tx72 ; 1,2 Send stuffing bit 299 | tx70: ; Send zero bit 300 | clr R12 ; 6 Clear stuffing count 301 | xor.b R9, &usbout ; 7,8,9,0 Toggle data lines 302 | tx71: ; 303 | dec R10 ; 1 Decrement octet count 304 | jne tx_data_loop ; 2,3 Next octet... 305 | ; 306 | ; 307 | .if !CRC_STYLE ; --- Send CRC -or- handshake (Sync + PID) 308 | ; Note: This sends inverted data because there is no 309 | ; time to invert the CRC 310 | txc0: ; - Bit 0/2/4/6/8/10/12/14 311 | rra R14 ; 4 Get a bit 312 | txc5: ; 313 | jc txc1 ; 5,6 If zero bit... 314 | ; One bit - no data lines toggle 315 | dec R12 ; 7 Increment bit stuffing count 316 | cmp #-6, R12 ; 8,9 Check if stuffing needed 317 | jne txc2 ; 0,1 No stuffing needed... 318 | nop ; 2 319 | jmp txc5 ; 3,4 Send stuffing bit 320 | txc1: ; Send zero bit 321 | xor.b R9, &usbout ; 7,8,9,0 Toggle data lines 322 | clr R12 ; 1 Clear stuffing count 323 | txc2: ; 324 | inc R10 ; 2 Increment bit pair count 325 | ; - Bit 1/3/5/7/9/11/13/15 326 | rra R14 ; 3 Get a bit 327 | txc6: ; 328 | jc txc3 ; 4,5 If zero bit... 329 | ; One bit - no data lines toggle 330 | dec R12 ; 7 Increment bit stuffing count 331 | cmp #-6, R12 ; 8,9 Check if stuffing needed 332 | jne txc4 ; 0,1 No stuffing needed... 333 | jmp txc6 ; 2,3 Send stuffing bit 334 | txc3: ; Send zero bit 335 | clr R12 ; 6 Clear stuffing count 336 | xor.b R9, &usbout ; 7,8,9,0 Toggle data lines 337 | txc4: ; 338 | cmp #8, R10 ; 1 Check if done with 8 bit pairs (16 bits) 339 | jne txc0 ; 2,3 Next bit pair... 340 | .endif ; 341 | ; 342 | ; --- Set SE0 state - EOP --- 343 | jmp $ + 2 ; 4,5 344 | ; 345 | bic.b #usbplus | usbminus, &usbout ; 6,7,8,9,0 Set SE0 and hold for two bit times (20 clock cycles) 346 | ; 347 | pop R8 ; 1,2 Restore saved registers 348 | pop R15 ; 3,4 349 | pop R14 ; 5,6 350 | pop R13 ; 7,8 351 | pop R12 ; 9,0 352 | pop R11 ; 1,2 353 | pop R10 ; 3,4 354 | pop R9 ; 5,6 355 | ; 356 | bis.b #usbminus, &usbout ; 7,8,9,0 Idle - J into line, required for EOP 357 | ; (Will be 1 cycle late if usbminus > 8) 358 | jmp $ + 2 ; 1,2 359 | jmp $ + 2 ; 3,4 360 | nop ; 5 361 | ; 362 | bic.b #usbplus | usbminus, &usbdir ; 6,7,8,9,0 Set data lines to input 363 | ; 364 | bic.b #usbplus, &usbifg ; Clear interrupt flag. 365 | ; 366 | reti ; Return from interrupt 367 | ; 368 | ; 369 | .end ; 370 | -------------------------------------------------------------------------------- /boot430.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2012 Kevin Timmerman 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | // 17 | // Ported to mspgcc by Chris Chung 2012.12 w/ the following changes 18 | // . adopt / implements logic from v-usb hid bootloader 19 | // . enhance skeleton and made into a bootloader frame 20 | // . remove 32khz xtal sync, only usb sync frame used to sync clock 21 | // 22 | // v0.91 release notes 23 | // 24 | // 2013.11 changes for v0.91 mainly contributed by "theprophet" (username at 43Oh.com) 25 | // . theprophet tried v0.90 and had numerous issues 26 | // . had provided various fixes to enable reliability on various platforms 27 | // . implement correct report_id according to usb standards 28 | // . implement a much more reliable timing scheme for data flashing and transfer 29 | // . bootloader is a bit slower but much more reliable 30 | // * if you use a led "heartbeat" blinker between P2.6 and P2.7, be sure to use a resistor 31 | // * if you have a choice, use a 3.6V LDO for better reliability 32 | // 33 | /* 34 | sample breadboard layout 35 | 36 | Vc Gnd 37 | +=====================================================+ 38 | | . . . . . . . . . . . . . . . . . | 39 | | . . . . . . . . . . . . . . . . . | 40 | | . . . . . . . . . . . . . . . . . | 41 | | . V G . . . . . . . . . . . . . . | 42 | | . . --+--+--+--+--+--+--+--+--+- . . . . . | 43 | | |- b6 b7 CK IO a7 a6 b5 b4 b3| | 44 | | |+ a0 a1 a2 a3 a4 a5 b0 b1 b2| | 45 | | . . --+--+--+--+--+--+--+--+--+- . . . . . | 46 | | . G V . . . . . . . . . . . . . . | 47 | | . . . . . . . . . . . . . . . . . | 48 | | . . . . . . . . . . . . . . . . . | 49 | | . . . D+ D- . . . . . . . . . . . . | 50 | +=====================================================+ 51 | +-o--o--o--o-+ 52 | | | | | | | 53 | | | | = = | jumper for D+ D- 54 | | | | | | | 55 | | | +[___]+ | 1k5 between D- and Vcc 56 | | | | | | | 57 | | +()+ | | | 10uF Cap 58 | | | o _ _ | 59 | | | |\ | || || 68ohm x 2 60 | | +-|o|| || || 61 | | | |/ |_||_|| LP2950 LDO 5V->3.3V 62 | | | o | | | 63 | | | | | | | 64 | | | | | | | 65 | | o o o o | 66 | 67 | V+ Gnd 68 | +=====================================================+ 69 | | . . . . . . . . . . . . . . . . . | 70 | | . . . . . . . . . . . . . . . . . | 71 | | . . . . . . . . . . . . . . . . . | 72 | | . . . +-----[ ]---+ . . . . . . . . | 73 | | . . . . . . . . . . . . . . . . . | 74 | | . . . . +--+--+--+--+--+--+--+--+--+ . . . | 75 | | |- b6 b7 CK IO a7 a6 b5 b4 b3| | 76 | | |+ a0 a1 a2 a3 a4 a5 b0 b1 b2| | 77 | | . . . . +--+--+--+--+--+--+--+--+--+ . . . | 78 | | . +----[ ]-+ . . . . . . . . . . . | 79 | | +----[ ]-+ . . . . . . . . . . . . | 80 | | . . (Vi-G-Vo) . . . . . . . . . . . . | 81 | | . . . +()+ . . . . . . . . . . . . | 82 | +=====================================================+ 83 | D+ D- 5v Gnd V+ 84 | 85 | */ 86 | 87 | #include 88 | #include "bbusb.h" 89 | 90 | //static uint8_t IrqInSendPacketBuffer[12]; 91 | static const uint8_t usb_packet_stall[] = 92 | { 93 | 1, USB_PID_STALL 94 | }; 95 | 96 | uint8_t TokenPacketBuffer[16]; 97 | uint8_t DataPacketBuffer[16] = { 0 }; 98 | uint8_t *ReadyForTransmitIrqIn = 0; 99 | unsigned CurrentAddress = 0; 100 | unsigned NewAddress = 0; 101 | unsigned Data_PID_ToggleIrqIn = USB_PID_DATA1; 102 | uint8_t *ReceiveBufferPointer = TokenPacketBuffer; 103 | 104 | #ifdef USE_32768HZ_XTAL 105 | static unsigned FrequencyCounter = 0; 106 | #endif 107 | 108 | extern unsigned Data_PID_Toggle; 109 | extern unsigned DataToTransmitOffset; 110 | extern const uint8_t *DataToTransmit; 111 | extern const uint8_t *ReadyForTransmit; 112 | 113 | 114 | 115 | //________________________________________________________________________________ 116 | 117 | int main(void) { 118 | 119 | //if (!(P1IN&usbminus)) usbwait = 0; // no usb D- pullup, no bootloader 120 | // no pull-up, app present, run app 121 | if (!(P1IN&usbminus) && (*((char*) *((uint16_t*) 0xffbe)) != -1)) 122 | asm("br &0xffbe"); 123 | 124 | WDTCTL = WDTPW | WDTHOLD; // Stop watchdog 125 | P1OUT = 0; // Prepare Port 1 126 | usbdir = ~(usbplus | usbminus); // USB lines are inputs 127 | //P1SEL |= BIT4; // SMCLK for measurements on P1.4 128 | 129 | P1DIR |= BIT5; 130 | 131 | #ifdef USE_32768HZ_XTAL 132 | BCSCTL1 = DIVA_3 | 15; // ACLK / 8, Range 15 133 | DCOCTL = 127; // ~15 MHz 134 | TACTL = TASSEL_2 | MC_2 | TACLR; // Continous up mode with clocking from SMCLK 135 | TACCTL0 = CM_1 | CCIS_1 | CAP | CCIE; // Setup CCR0 for capturing on rising edges of ACLK with enabled interrupts 136 | __eint(); 137 | #else 138 | P2SEL = 0; 139 | P2DIR = BIT6|BIT7; // indicator led 140 | P2OUT = 0; 141 | 142 | BCSCTL1 = 15; // Range 15 143 | DCOCTL = 127; // ~15 MHz 144 | #endif 145 | 146 | __delay_cycles(2000000); // Allow some time to stabilize power 147 | uint8_t usbwait=12; 148 | 149 | 150 | usbies = 0; // Interrupt on rising edge of D+ because there is keep-alive signaling on 151 | // D- that would cause false syncs 152 | usbifg = 0; // No interrupt pending 153 | 154 | uint16_t addrStart=0, addrEnd=0, addrCurrent=0, addrSave=0; 155 | uint8_t initialized=0; 156 | uint16_t heartbeat = 0; 157 | 158 | uint8_t idx=0, inBuf[48]; 159 | uint8_t *buffUp=0; 160 | uint8_t next_time_flash_erase = 0; 161 | 162 | static uint16_t const USB_IDLE_DETECT_THRESHOLD = 16384; 163 | uint16_t usb_idle_detect_counter = 0; 164 | uint8_t usb_idle = 0; 165 | 166 | /* What is this usb idle thing ? 167 | We are in a bootloader, its aim is to receive via usb a new 168 | program to be flashed. But erasing and writing to flash takes 169 | quite a big time, and usb timing is tight. The usb protocol 170 | needs that response packets be sent within a certain time 171 | frame, and if the mcu misses that time frame, the host can 172 | consider the device as malfunctioning. 173 | The idea behind the usb idle thing is to delay operations that 174 | take time to a moment where we hope the mcu will not have any 175 | usb packet to answer. 176 | Specifically : 177 | 1. when the host side sends an address where flash must be 178 | erased, the host sleeps for a certain amount T of milliseconds 179 | before sending another command. Within T milliseconds, the 180 | mcu has time to answer remaining usb packets and erase the 181 | requested flash segment. 182 | 2. when the host side sends payload bytes (which are bytes of 183 | the program to be flashed), the mcu has no time to write them 184 | into flash and answer usb packets. It stores them in a small 185 | RAM buffer, and writes them to flash once the host sleeps a 186 | bit. Here, the host sends 32 bytes before sleeping and letting 187 | the mcu write those bytes to flash. 188 | To detect usb idle, we simply count how many "for-ever" loops we 189 | have done since last received usb packet, and beyond a threshold, 190 | we consider being in usb idle mode, that is to say : we consider 191 | the host will not send any other usb packet before we have 192 | finished with flashing and being able to handle a new usb packet. 193 | */ 194 | 195 | for (;;) // for-ever 196 | { 197 | // Detect USB idle 198 | if(initialized && !usb_idle) 199 | { 200 | usb_idle_detect_counter++; 201 | if(usb_idle_detect_counter > USB_IDLE_DETECT_THRESHOLD) 202 | usb_idle = 1; 203 | } 204 | 205 | if (!heartbeat++) 206 | { 207 | if (initialized) // usb reset from host occured 208 | { 209 | P2OUT ^= BIT6; 210 | }//if 211 | else 212 | { // no reset, run app if present 213 | //if (!usbwait && (*((char*) 0xc000) != -1)) { 214 | if (!usbwait && (*((char*) *((uint16_t*) 0xffbe)) != -1)) 215 | { 216 | _BIC_SR(GIE); 217 | TACTL = 0; 218 | P2DIR = P1DIR = 0; 219 | P2OUT = P1OUT = 0; 220 | asm("br &0xffbe"); 221 | } 222 | else 223 | { 224 | usbwait--; 225 | } 226 | } 227 | } 228 | 229 | unsigned n = 80; // Reset if both D+ and D- stay low for a while 230 | // 10 ms in SE0 is reset 231 | // Should this be done in the ISR somehow??? 232 | while (!initialized && !(usbin & (usbplus | usbminus))) 233 | { 234 | if (!--n) 235 | { 236 | CurrentAddress = 0; // Device has initial address of 0 237 | NewAddress = 0; // 238 | addrCurrent = addrStart = addrEnd = 0; 239 | 240 | #ifndef USE_32768HZ_XTAL 241 | if (!initialized) 242 | { 243 | TACTL = TASSEL_2 | MC_2 | TACLR; // Continous up mode with clocking from SMCLK 244 | initialized = 1; 245 | //P2OUT |= BIT6; // debug use, led indicate we are trying sync 246 | n = 1000; // time to stabilize clock 247 | while (--n) 248 | { 249 | while (!(usbin&usbminus)); 250 | TACTL |= TACLR; 251 | while ((usbin&usbminus)); 252 | if (TAR < 15000) ++DCOCTL; 253 | else --DCOCTL; 254 | } 255 | usbie = usbplus; 256 | _BIS_SR(GIE); 257 | } 258 | #else 259 | usbie = usbplus; 260 | _BIS_SR(GIE); 261 | initialized = 1; 262 | #endif 263 | 264 | break; 265 | } 266 | } 267 | 268 | 269 | if(DataPacketBuffer[0]) // Check if the USB SIE has received a packet 270 | { 271 | uint8_t packet_size = *DataPacketBuffer; // we save packet_size here to avoid it being 272 | DataPacketBuffer[0] = 0; // overwritten by "fast" status packet that follows 273 | usb_idle_detect_counter = 0; 274 | usb_idle = 0; 275 | 276 | // At the end of the buffer is the PID of the preceding token packet 277 | // Check if it is a SETUP packet 278 | if(DataPacketBuffer[15] == USB_PID_SETUP) 279 | { 280 | // Handle the packet, get a response 281 | if((DataToTransmit = ProtocolSetupPacket(DataPacketBuffer))) 282 | { 283 | // Setup to send the response 284 | Data_PID_Toggle = USB_PID_DATA0; 285 | DataToTransmitOffset = 1; 286 | } 287 | else 288 | { 289 | // Send STALL PID if there is no response 290 | ReadyForTransmit = usb_packet_stall; 291 | } 292 | } 293 | else if (DataPacketBuffer[15] == USB_PID_OUT) // Check if it is an OUT packet 294 | { 295 | // will be getting stuffs here 296 | // incoming LL-PP-RI-(d0-d1-d2-d3-d4-d5)-C1-C2 297 | // ex. 0a-4b-01-(00-4b-0e-8d-0d-4e)-56-fa 298 | // LL - length, ours are always 0a or 08 299 | // PP - PID, should only be DATA0 or DATA1 (0xc3 or 0x4b) - 4b for us 300 | // RI - application level control byte - the HID report id. Here : 301 | // == 1, request flash write, start address / length follows 302 | // == 2, no special instruction, just carry data 303 | // d? - firmware data, each packet carries up to LL-4 bytes of data 304 | // for report id 1 : report count = 6, LL = 0a, data bytes = 6 305 | // for report id 2 : report count = 4, LL = 08, data bytes = 4 306 | // C? - packet checksum, application does not use these 307 | // 308 | 309 | uint8_t *cp = DataPacketBuffer+2; 310 | //if (*DataPacketBuffer == 0x0A && *cp == 0x01) 311 | if (packet_size == 0x0A) 312 | { // flash write request (report id 1) 313 | cp++; 314 | addrCurrent = addrStart = (*cp<<8) + *(cp+1); // get start address high bytes 315 | cp += 2; 316 | addrEnd = (*cp<<8) + *(cp+1); 317 | //______________ interrupt vector, don't do immediate flash write 318 | if (addrStart >= 0xff00) 319 | { 320 | buffUp = inBuf; 321 | } 322 | else 323 | { 324 | addrSave = addrEnd; 325 | buffUp = 0; 326 | idx = 0; 327 | next_time_flash_erase = 1; 328 | } 329 | } 330 | //else if (*DataPacketBuffer == 0x08 && *cp == 0x02) 331 | else if (packet_size == 0x08) 332 | { 333 | uint8_t c=0; // receive bytes (report id 2) 334 | cp++; // skip report id 335 | if (buffUp) // we are receiving interrupt vector bytes 336 | { 337 | for (c=0;c<4;c++) 338 | *((uint8_t *) buffUp++) = *cp++; 339 | addrCurrent += 4; 340 | } 341 | else 342 | { // we are receiving normal data 343 | for (c=0;c<4;c++) 344 | inBuf[c+idx] = *cp++; 345 | idx += 4; 346 | } 347 | } 348 | 349 | } // else if USB_PID_OUT 350 | //DataPacketBuffer[0] = 0; // Done with received packet, don't process again, allow USB SIE to receive the next packet 351 | } // if USB SIE has received a packet 352 | 353 | // Check if an outgoing packet needs chunking and the USB SIE 354 | // is ready for it 355 | if (DataToTransmit && !ReadyForTransmit) 356 | { 357 | PacketGenerator(); // Make a chunk with CRC 358 | } 359 | 360 | if (!ReadyForTransmitIrqIn) 361 | { // Check if the USB SIE is ready for an endpoint 1 packet 362 | /* 363 | IrqIn(IrqInSendPacketBuffer); // Build the packet 364 | CRC(IrqInSendPacketBuffer); // Append CRC 365 | ReadyForTransmitIrqIn = IrqInSendPacketBuffer; // Send it 366 | */ 367 | } 368 | 369 | 370 | // We have received interrupt vector address, and data bytes. 371 | // USB is idle which means we can write to flash 372 | if(usb_idle && buffUp && addrCurrent > addrStart && addrStart >= 0xff00) 373 | { 374 | //_____ we doing interrupt vector, so don't be interrupted 375 | uint16_t savIntr = *((uint16_t *) 0xffe4); 376 | uint16_t savReset = *((uint16_t *) 0xfffe); 377 | _BIC_SR(GIE); 378 | FCTL1 = FWKEY+ERASE; 379 | FCTL3 = FWKEY; 380 | *((uint8_t *) 0xff00) = 0; 381 | FCTL1 = FWKEY+WRT; 382 | 383 | uint8_t *dp = (uint8_t *) 0xffa0; 384 | uint8_t *vp = (uint8_t *) 0xffe0; 385 | uint8_t *cp = inBuf; 386 | uint8_t i=0x20; 387 | while (i--) *dp++ = *cp++; // write to flash backup copy 388 | 389 | *((uint16_t *) (inBuf+4)) = savIntr; // use bootloader's interrupt 390 | *((uint16_t *) (inBuf+30)) = savReset;// reset goes to bootloader 391 | 392 | i=0x20; cp = inBuf; 393 | while (i--) *vp++ = *cp++; // write to flash real vector 394 | *((uint16_t *) (0xff80)) = addrSave; // save application's end address 395 | *((uint16_t *) (0xffde)) = 0xaa55; // disable factory BSL 396 | buffUp = 0; 397 | FCTL1 = FWKEY; 398 | FCTL3 = FWKEY+LOCK; 399 | 400 | _BIS_SR(GIE); 401 | } 402 | 403 | 404 | // We have received addresses. USB is idle : erase flash. 405 | if(usb_idle && next_time_flash_erase) 406 | { 407 | FCTL2 = FWKEY+FSSEL0+(30); 408 | FCTL1 = FWKEY+ERASE; 409 | FCTL3 = FWKEY; 410 | *((uint8_t *) addrCurrent) = 0; 411 | FCTL1 = FWKEY+WRT; 412 | next_time_flash_erase = 0; 413 | } 414 | 415 | 416 | // We have received data bytes, and USB is idle : flash them. 417 | if(usb_idle && !buffUp && addrStart < 0xff00 && idx) 418 | { 419 | uint8_t c=0; 420 | for(c = 0; c < idx; c++) 421 | *((uint8_t *) addrCurrent++) = inBuf[c]; 422 | idx = 0; 423 | 424 | if (!(addrCurrent&0x01ff)) 425 | { 426 | //____ we are crossing 512byte/block boundary 427 | //____ erase and get ready for next block 428 | FCTL1 = FWKEY+ERASE; 429 | FCTL3 = FWKEY; 430 | *((uint8_t *) addrCurrent) = 0; 431 | FCTL1 = FWKEY+WRT; 432 | } 433 | } 434 | 435 | 436 | if(addrCurrent >= addrEnd && !buffUp) // !buffUp means that we have handled the interrupt vector in an usb idle time 437 | { 438 | //____ lockup flash, we are over. 439 | FCTL1 = FWKEY; 440 | FCTL3 = FWKEY+LOCK; 441 | 442 | addrCurrent = addrStart = addrEnd = 0; 443 | idx = 0; 444 | } 445 | 446 | }//for-ever 447 | } 448 | 449 | 450 | #ifdef USE_32768HZ_XTAL 451 | #pragma vector = TIMER0_A0_VECTOR // Timer A CCR0 interrupt 452 | __interrupt void dco_adjust(void) // 453 | { // 454 | TA0CCTL0 &= ~CCIFG; // Clear interrupt flag 455 | __eint(); // Re-enable interrupts to allow fast response to USB 456 | // Adjust DCO 457 | // 15,000,000 / (32,768 / 8) = 3662.11 458 | // 3662.5 * (32,768 / 8) = 15,001,600 459 | if((TA0CCR0 - FrequencyCounter) < 3662) ++DCOCTL; else --DCOCTL; 460 | FrequencyCounter = TA0CCR0; // 461 | } // 462 | #endif 463 | 464 | -------------------------------------------------------------------------------- /boot430.hex: -------------------------------------------------------------------------------- 1 | :10F000005542200135D0085A82454802314000045B 2 | :10F010003F4010000F9308249242480220012F83A2 3 | :10F020009F4FD0F90002F8233F4038000F93072488 4 | :10F030009242480220011F83CF431002F92331502E 5 | :10F04000CAFF5F4220002FF307201F42BEFFFF933D 6 | :10F05000000002241042BEFFB240805A2001C24389 7 | :10F060002100F240FCFF2200F2D020002200C24327 8 | :10F070002E00F240C0FF2A00C2432900F2400F00D8 9 | :10F080005700F2407F0056003E400B003F401E2CD0 10 | :10F090001F83FE231E83FC230343C2432400C24379 11 | :10F0A00023008143320046430B434443C1433000B5 12 | :10F0B000814334000A4305430943F1400C00310009 13 | :10F0C000474308430C3CC193300007244793052075 14 | :10F0D00018533890014001285743915332008193CF 15 | :10F0E00032002220C19330000624F2E040002900C3 16 | :10F0F000D1433000533CC193310013201F42BEFF67 17 | :10F10000FF9300000E2432C282436001C2432200FA 18 | :10F11000C2432A00C2432100C24329001042BEFF5D 19 | :10F12000343CF1533100313CC19330002E24D143A3 20 | :10F130003000343C3E532B208243120282431002A3 21 | :10F14000B240240260013F40E803143C5E422000CC 22 | :10F150002EF3FC27A2D260015E4220002EF3FC2396 23 | :10F160001E4270013E90983A032CD2535600023C46 24 | :10F17000F25356003F53EA23D243250032D2D14303 25 | :10F1800030000A4305430943093C3E4050005F42BA 26 | :10F1900020003FF00300CE27C14330005E4216023C 27 | :10F1A0004E937724C24316025F4225027F902D00C2 28 | :10F1B00016203F401602B012A0F4824F26020F9391 29 | :10F1C0000824B240C3000402924346024743084366 30 | :10F1D000603CB24024F92802474308435A3C7F90E0 31 | :10F1E000E1FF49207E900A0014205942190289103B 32 | :10F1F0005F421A02095F55421B0285105F421C02E2 33 | :10F20000055F399000FF3A280A49474308430B41FC 34 | :10F21000403C7E923C200B931124DB4219020000FB 35 | :10F22000DB421A020100DB421B020200DB421C022D 36 | :10F2300003002B522A52474308432B3C4F440E41B4 37 | :10F240000E5FDE42190200001E430E510E5FDE42C9 38 | :10F250001A0200002E430E510E5FDE421B02000018 39 | :10F260003E4003000E510F5EDF421C02000064525C 40 | :10F27000474308430E3C474308430B3C8145340059 41 | :10F280000A494743084356430B434443023C474320 42 | :10F290000843829326020524829328020220B0129A 43 | :10F2A00044F4479374240B938624099A842C399050 44 | :10F2B00000FF81281C42E4FF1D42FEFF32C2B24023 45 | :10F2C00002A52801B24000A52C01C24300FFB240B4 46 | :10F2D00040A528010E413F40A0FFFF4E00001F53F4 47 | :10F2E0003F90C0FFFA23814C0400814D1E000E4167 48 | :10F2F0003F40E0FFFF4E00001F53FC2392413400CB 49 | :10F3000080FFB24055AADEFFB24000A52801B240FE 50 | :10F3100010A52C0132D20B434E3CB2405EA52A010F 51 | :10F32000B24002A52801B24000A52C01CA4300004A 52 | :10F33000B24040A52801413C399000FF222C449363 53 | :10F3400022240E4A0D410D8A053C0F4D0F5EEE4FF3 54 | :10F3500000001E534F4E4F8A4F94F72B44440A54DB 55 | :10F360003AB0FF011220B24002A52801B24000A528 56 | :10F370002C01CA430000B24040A528014643444343 57 | :10F38000063C4643043C4643023C464344430A95FC 58 | :10F39000022C3040C6F00B9302243040C6F0B2403D 59 | :10F3A00000A52801B24010A52C0144430A4305439F 60 | :10F3B00009433040C6F04693B0230B93BD27464324 61 | :10F3C000E63F32D0F000FD3F304022F90B126E4F85 62 | :10F3D0004C4E0C5F6E53CF4E00002F533E43283CE3 63 | :10F3E0007D4F0DEE8E104E4E1DB302243EE0C1C087 64 | :10F3F0002DB302243EE081C12DB202243EE001C3C0 65 | :10F400003DB202243EE001C63DB0100002243EE0C1 66 | :10F4100001CC3DB0200002243EE001D83DB04000C8 67 | :10F4200002243EE001F03DF0800002243EE001A015 68 | :10F430000C9FD62F3EE3CF4E00008E10CF4E010022 69 | :10F440003B4130410B121F4226021B4246020E4F27 70 | :10F450000E5B6C4F0C5F1F4204023FE08800824F3E 71 | :10F460000402C24F2B020F433D402C020C9E032C82 72 | :10F4700082432602063CFD4E00001D531F533F925F 73 | :10F48000F5230B5F824B46025F53C24F2A023F4077 74 | :10F490002A02B012CCF3B2402A0228023B4130418A 75 | :10F4A0005E4F02003EF0200019245F4F03005F937F 76 | :10F4B00006245A287F50F7FF6F93562C523CD242B5 77 | :10F4C00080FF0B02D24281FF0C02D242F10F0D02EB 78 | :10F4D000D242F00F0E023F4007023041FF900C0075 79 | :10F4E0000300422C5E4F03000E5E104E26F93F4093 80 | :10F4F0003FF93041D24F04001002C2431102313CA7 81 | :10F500005E4F05006E9310247E900300032C5E93E3 82 | :10F510002820073C7E9003000E247E9022002120AC 83 | :10F52000183C3F4042F93041FF90090008001E207E 84 | :10F530003F4055F930415F4F04005F931A24032880 85 | :10F540006F930720033C3F4082F930413F409CF9D4 86 | :10F5500030413F40ADF9304182431402B2404B008C 87 | :10F5600002023F403EF930410F4330413F405FF9D6 88 | :10F5700030413F4087F93041FF40030000001E4208 89 | :10F5800002023EE08800824E0202CF4E0100CF43CD 90 | :10F590000200CF430300304112021002280214027D 91 | :10F5A0001602000236024AF801D2015A011E3C41FD 92 | :10F5B0003B413A413941D2C323000013F2900F007E 93 | :10F5C000570002241042A4FF09120A1239402000F9 94 | :10F5D0002A436AB904246AB902246AB9EA236AB9D7 95 | :10F5E00006206AB904206AB902206AB9E2270B1220 96 | :10F5F0006A496B492AB302282BB30128003C0C123C 97 | :10F6000003436A492AB31A28003C6A496B492AB362 98 | :10F6100002282BB30128003C003C003C6A492AB375 99 | :10F620000D28003C6A496B492AB302282BB30128F4 100 | :10F63000003C003C003C6A492AB3B92F003C003C26 101 | :10F64000003C6A493C407F002AF34C100D120D43E8 102 | :10F650006B490AEB2AF34C100E123E4000026A4935 103 | :10F660000BEA2BF34C100F122F4E6B490AEB2AF3C7 104 | :10F670004C1008123840FC006A490BEA2BF34C107E 105 | :10F68000413C6A490BEA2BF34C100D433EE30CB8A6 106 | :10F6900007206A493AF003006D243CD080001DE346 107 | :10F6A0006B493BF0030066240AEB2AF34C100CB8BC 108 | :10F6B0006A4908200B4A03433CD080002DE30343F2 109 | :10F6C0006A49003C0BEA2BF34C100CB807206A493E 110 | :10F6D0003AF003004F243CD080002DE26B490AEB46 111 | :10F6E0002AF34C10CF4E00000CB86A4908200B4A90 112 | :10F6F00003433CD080003DE203436A49003C0BEAEF 113 | :10F700002BF34C100CB808206A493AF0030032245D 114 | :10F710003CD080003DE010006B490AEB2AF34C100E 115 | :10F720001F5303430CB808206B493BF0030022240D 116 | :10F730003CD080003DE020006A490BEA2BF34C10DE 117 | :10F74000003C0CB808206A493AF0030013243CD06E 118 | :10F7500080003DE040006B490AEB2AF34C100E4C50 119 | :10F760000ECD0CB88E236B492BF33CD080000343A5 120 | :10F77000003C873FD2C32300CF4E00001E42000250 121 | :10F780000F8ECE4F0000003C003C5A4E01005B4EF5 122 | :10F7900002005C4E03003BB080000C6C3CF00F009C 123 | :10F7A0003BC080003A90690022243A90E1003F2457 124 | :10F7B0003A902D003C24B290160200020920B2407B 125 | :10F7C000360200023A90C3003B243A904B003824A2 126 | :10F7D00038413F413E413D413C413B41D2B3230092 127 | :10F7E000F52E3A413941D2B32300EE2E0013C29BCD 128 | :10F7F0001202EE231C9305201F42140282431402BE 129 | :10F80000043C1F422802824328020F9304203F40F9 130 | :10F81000AAF530404AF88F93000005249242100266 131 | :10F82000120230404AF83F40ACF530404AF8C29BE3 132 | :10F830001202CE23C24A2502B24016020002C83F7D 133 | :10F840003F40A8F530404AF80013D2C32100E2D36C 134 | :10F85000210039400300C2D922007A4F1A533B409D 135 | :10F8600080000C430B1106281C833C90FBFF052CE9 136 | :10F870000343F93FC2E921000C4308430B11034342 137 | :10F8800005281C833C90FBFF042CF93FC2E92100B2 138 | :10F890000C430B11034305281C833C90FBFF042CF5 139 | :10F8A000F93F0C43C2E9210018E3E8230B1103439D 140 | :10F8B00005281C833C90FBFF042CF93FC2E9210082 141 | :10F8C0000C437D4F0B1106281C833C90FBFF052C3D 142 | :10F8D0000343F93FC2E921000C430B110B4D0528EE 143 | :10F8E0001C833C90FBFF042CF93F0C43C2E9210030 144 | :10F8F0001A83B823003CF2C00300210038413F4185 145 | :10F900003E413D413C413B413A413941E2D3210036 146 | :10F91000003C003C0343F2C003002200D2C323009A 147 | :04F9200000130013BD 148 | :10F92400011EEEF468F568F568F568F5F4F400F581 149 | :10F9340068F568F562F568F558F5000200001212E2 150 | :10F9440001100100000008C016DF050100010200DB 151 | :10F954000109090222000101008032220902220069 152 | :10F9640001010080320904000001030000000921A4 153 | :10F9740001010001222100070581030800C80404D5 154 | :10F98400030904141403730069006D0070006C0013 155 | :10F99400650061007600720010100362006F006F52 156 | :10F9A400007400340033003000210600FF0901A177 157 | :10F9B40001150026FF007508850195060900B202AD 158 | :0CF9C40001850295040900B20201C00098 159 | :10F9D00036024B00C300040701005BFFFFFFFF007E 160 | :10FFE00048F848F8BCF548F848F848F848F848F8A0 161 | :10FFF00048F848F848F848F848F848F848F800F051 162 | :040000030000F00009 163 | :00000001FF 164 | -------------------------------------------------------------------------------- /commandline/Makefile: -------------------------------------------------------------------------------- 1 | # Name: Makefile 2 | # Project: Automator 3 | # Author: Christian Starkjohann 4 | # Creation Date: 2006-02-01 5 | # Tabsize: 4 6 | # Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH 7 | # License: Proprietary, free under certain conditions. See Documentation. 8 | # This Revision: $Id$ 9 | 10 | # Please read the definitions below and edit them as appropriate for your 11 | # system: 12 | 13 | # Use the following 3 lines on Unix and Mac OS X: 14 | #USBFLAGS= `libusb-config --cflags` 15 | #USBLIBS= `libusb-config --libs` 16 | #EXE_SUFFIX= 17 | 18 | # Use the following 3 lines on Windows and comment out the 3 above: 19 | USBFLAGS= 20 | USBLIBS= -lhid -lusb -lsetupapi 21 | EXE_SUFFIX= .exe 22 | 23 | CC= gcc 24 | CXX= g++ 25 | CFLAGS= -O2 -Wall $(USBFLAGS) 26 | LIBS= $(USBLIBS) 27 | ARCH_COMPILE= 28 | ARCH_LINK= 29 | 30 | OBJ= main.o usbcalls.o 31 | PROGRAM= boot430load$(EXE_SUFFIX) 32 | 33 | all: $(PROGRAM) 34 | 35 | $(PROGRAM): $(OBJ) 36 | $(CC) $(ARCH_LINK) $(CFLAGS) -o $(PROGRAM) $(OBJ) $(LIBS) 37 | 38 | 39 | strip: $(PROGRAM) 40 | strip $(PROGRAM) 41 | 42 | clean: 43 | rm -f $(OBJ) $(PROGRAM) 44 | 45 | .c.o: 46 | $(CC) $(ARCH_COMPILE) $(CFLAGS) -c $*.c -o $*.o 47 | -------------------------------------------------------------------------------- /commandline/boot430load.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simpleavr/boot430/f41172a1bcb151ed221e92bc3d059c2d2b46e2d5/commandline/boot430load.exe -------------------------------------------------------------------------------- /commandline/hidsdi.h: -------------------------------------------------------------------------------- 1 | /* Name: hidsdi.h 2 | * Project: usbcalls library 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2006-02-02 5 | * Tabsize: 4 6 | * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: Proprietary, free under certain conditions. See Documentation. 8 | * This Revision: $Id$ 9 | */ 10 | 11 | /* 12 | General Description 13 | This file is a replacement for hidsdi.h from the Windows DDK. It defines some 14 | of the types and function prototypes of this header for our project. If you 15 | have the Windows DDK version of this file or a version shipped with MinGW, use 16 | that instead. 17 | */ 18 | 19 | #ifndef _HIDSDI_H 20 | #define _HIDSDI_H 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | typedef struct{ 28 | ULONG Size; 29 | USHORT VendorID; 30 | USHORT ProductID; 31 | USHORT VersionNumber; 32 | }HIDD_ATTRIBUTES; 33 | 34 | void __stdcall HidD_GetHidGuid(OUT LPGUID hidGuid); 35 | 36 | BOOLEAN __stdcall HidD_GetAttributes(IN HANDLE device, OUT HIDD_ATTRIBUTES *attributes); 37 | 38 | BOOLEAN __stdcall HidD_GetManufacturerString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen); 39 | BOOLEAN __stdcall HidD_GetProductString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen); 40 | BOOLEAN __stdcall HidD_GetSerialNumberString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen); 41 | 42 | BOOLEAN __stdcall HidD_GetFeature(IN HANDLE device, OUT void *reportBuffer, IN ULONG bufferLen); 43 | BOOLEAN __stdcall HidD_SetFeature(IN HANDLE device, IN void *reportBuffer, IN ULONG bufferLen); 44 | 45 | BOOLEAN __stdcall HidD_GetNumInputBuffers(IN HANDLE device, OUT ULONG *numBuffers); 46 | BOOLEAN __stdcall HidD_SetNumInputBuffers(IN HANDLE device, OUT ULONG numBuffers); 47 | 48 | #include 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /commandline/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | boot430loader 3 | 4 | chris chung 2013 January 5 | www.simpleavr.com 6 | 7 | . supports msp430g2553 only 8 | 9 | borrow heavily / derived from .. 10 | * Project: AVR bootloader HID 11 | * Author: Christian Starkjohann 12 | * Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH 13 | * License: Proprietary, free under certain conditions. See Documentation. 14 | * This Revision: $Id$ 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "usbcalls.h" 24 | 25 | #define IDENT_VENDOR_NUM 0x16c0 26 | #define IDENT_VENDOR_STRING "simpleavr" 27 | #define IDENT_PRODUCT_NUM 1503 28 | #define IDENT_PRODUCT_STRING "boot430" 29 | 30 | //________________________________________________________________________________ 31 | char *usbErrorMessage(int errCode) 32 | { 33 | static char buffer[80]; 34 | 35 | switch(errCode){ 36 | case USB_ERROR_ACCESS: return "Access to device denied"; 37 | case USB_ERROR_NOTFOUND: return "The specified device was not found"; 38 | case USB_ERROR_BUSY: return "The device is used by another application"; 39 | case USB_ERROR_IO: return "Communication error with device"; 40 | default: 41 | sprintf(buffer, "Unknown USB error %d", errCode); 42 | return buffer; 43 | } 44 | return NULL; /* not reached */ 45 | } 46 | 47 | //________________________________________________________________________________ 48 | int main(int argc, char *argv[]) 49 | { 50 | if (argc < 2) 51 | { 52 | printf("\nusage: %s \n\n", argv[0]); 53 | }//if 54 | 55 | usbDevice_t *dev = NULL; 56 | int err=0; 57 | //_______________________ try device 58 | if ((err = usbOpenDevice(&dev, 59 | IDENT_VENDOR_NUM, 60 | IDENT_VENDOR_STRING, 61 | IDENT_PRODUCT_NUM, 62 | IDENT_PRODUCT_STRING, 1)) != 0) 63 | { 64 | fprintf(stderr, "Error opening HIDBoot device: %s\n", usbErrorMessage(err)); 65 | }//if 66 | 67 | char reportBuf[32] = { 0, 0, 0, 0, 0, 0, 0, 0, }; 68 | union 69 | { 70 | char val[32]; 71 | struct 72 | { 73 | unsigned char dummy; 74 | unsigned char report_id; 75 | unsigned char version; 76 | unsigned char release; 77 | unsigned short end_flash; 78 | unsigned short device; 79 | } info; 80 | } report; 81 | int len = sizeof(reportBuf); 82 | if (!err && (err = usbGetReport(dev, USB_HID_REPORT_TYPE_FEATURE, 1, report.val+1, &len)) != 0) 83 | { 84 | fprintf(stderr, "Error reading page size: %s\n", usbErrorMessage(err)); 85 | }//if 86 | 87 | printf("\ndevice (%04x), version (%d.%d), application end at (0x%04x)\n\n", 88 | report.info.device, report.info.version, report.info.release, report.info.end_flash); 89 | 90 | int flash_start = 0xe000; // default is 8k flash 91 | 92 | if (report.info.device >= 0x2500) 93 | flash_start = 0xc000; // device is 16k 94 | 95 | 96 | /* When using usbSetReport() with USB_HID_REPORT_TYPE_FEATURE, you will 97 | have to send a buffer with the following constraints : 98 | - the first byte must be the report id 99 | - the report id must be one of those declared by the hid descriptor (here, 1 or 2 -- see HID_Descriptor in bbusb_protocol.c) 100 | - the number of data bytes must be equal to the report count of chosen report id (here, 6 for report id 1, and 4 for report id 2 -- see HID_Descriptor in bbusb_protocol.c) 101 | - the data bytes must follow the report id 102 | - the total length of the buffer must be the data bytes + 1 for the report id 103 | 104 | For instance, we want to send 6 bytes 0xBA of data using report id 1. The hid descriptor 105 | tells us that it is possible (report id 1 exists and report count == 6 bytes), and the 106 | whole buffer will be as follows : 0x01 0xBA 0xBA 0xBA 0xBA 0xBA 0xBA . We will call : 107 | char buffer[7] = { 0x01, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA }; 108 | usbSetReport(dev, USB_HID_REPORT_TYPE_FEATURE, buffer, 7); 109 | 110 | On the MCU device side, we will receive exactly this usb packet in DataPacketBuffer : 111 | // 0a 4b 01 ba ba ba ba ba ba c1 50 112 | // LL D1 RI d0 d1 d2 d3 d4 d5 C1 C2 113 | with 114 | LL : length (without the LL byte itself). Here we sent 6 bytes + 1 report id byte + 2 checksum bytes + DATA1 = 0a. 115 | D1 : DATA1 (0x4b) since using endpoint 1, else it would be DATA0 (0xc3) for endpoint 0. 116 | RI : report id 117 | d0..d5 : user-supplied data 118 | C1..C2 : CRC16 checksum 119 | */ 120 | 121 | 122 | //_______________________ try open hex file 123 | if (!err && argc >= 2) 124 | { 125 | FILE *fp = fopen(argv[1], "r"); 126 | if (fp) 127 | { 128 | int addrStart=0, addrEnd=0; 129 | unsigned char data[16*1024]; // 16k flash space 130 | char line[80]; 131 | union 132 | { 133 | unsigned char val[36]; 134 | struct 135 | { 136 | unsigned char len; 137 | unsigned char addrH; 138 | unsigned char addrL; 139 | unsigned char type; 140 | unsigned char data[32]; 141 | } set; 142 | } raw; 143 | 144 | memset(data, 0xff, sizeof(data)); 145 | //___________________ take in file 146 | while (fgets(line, 80, fp)) 147 | { 148 | //printf("read: %s", line); 149 | //:10E000005542200135D0085A8245040231400003B0 150 | char sav, *cp = line+1; 151 | int i=0; 152 | while (*cp>='0') { 153 | sav = *(cp+2); 154 | *(cp+2) = '\0'; 155 | raw.val[i++] = (unsigned char) strtol(cp, NULL, 16); 156 | cp += 2; 157 | *cp = sav; 158 | }//while 159 | //_______________ load our big buffer 160 | if (!raw.set.type) 161 | { 162 | int offset = raw.set.addrH; 163 | offset *= 256; 164 | offset -= flash_start; 165 | if (offset < 0) 166 | { 167 | printf("\nfirmware out of range for device 0x%04x < 0x%04x\n\n", offset + flash_start, flash_start); 168 | addrStart = addrEnd = 0; 169 | break; 170 | }//if 171 | offset += raw.set.addrL; 172 | if (raw.set.addrH < 0xff) 173 | { 174 | if (offset <= addrStart) addrStart = offset; 175 | if ((offset+raw.set.len) > addrEnd) addrEnd = offset + raw.set.len; 176 | }//if 177 | cp = (char *) data + offset; 178 | printf("offset..%04x (%d)\n", offset, raw.set.len); 179 | for (i=0;i 0x%04x (0x%04x)\n", addrStart, addrEnd, addrEnd-addrStart); 191 | #define TK 0x0a 192 | 193 | //___________________ now do flash 194 | if (addrEnd > addrStart) 195 | { 196 | char instr = 0x10; 197 | int bcnt=0; 198 | while (addrStart < addrEnd) 199 | { 200 | char buf[16]; 201 | int report_size = 0; 202 | int i=0; 203 | 204 | if (instr == 0x10) // command to send address 205 | { 206 | buf[i++] = 0x01; // flash write request (report id 1) 207 | buf[i++] = addrStart>>8; 208 | buf[i++] = addrStart&0xff; 209 | buf[i++] = addrEnd>>8; 210 | buf[i++] = addrEnd&0xff; 211 | report_size = 7; // adjust length (report size + 1) 212 | }//if 213 | else 214 | { 215 | buf[0] = 0x02; // data bytes (report id 2) 216 | for (i=1;i<5;i++) 217 | { 218 | buf[i] = data[(addrStart++)-flash_start]; 219 | printf(" %02x", (unsigned char) buf[i]); 220 | bcnt++; 221 | }//for 222 | report_size = 5; // adjust length (report size + 1) 223 | }//else 224 | 225 | printf(" (%03x)", bcnt); 226 | int relax = 0; 227 | if ((bcnt/32) || (instr == 0x10) || (addrStart>=addrEnd)) 228 | { 229 | relax = 1; 230 | bcnt = bcnt % 32; 231 | printf("* %04x/%04x", addrStart, addrEnd); 232 | if(instr == 0x10) 233 | printf(" Erasing flash block..."); 234 | else 235 | printf(" Writing data to flash memory..."); 236 | }//if 237 | instr = TK; 238 | 239 | printf("\n"); 240 | if (!err && (err = usbSetReport(dev, USB_HID_REPORT_TYPE_FEATURE, buf, report_size)) != 0) 241 | { 242 | //if (!relax) { 243 | printf("\n"); 244 | fprintf(stderr, "Error uploading data block: %s\n", usbErrorMessage(err)); 245 | break; 246 | //}//if 247 | }//if 248 | //uSleep(2500); 249 | uSleep(500); 250 | 251 | //~ boost::this_thread::sleep(boost::posix_time::microseconds(500*1000)); 252 | if(buf[0] == 0x01 || relax) // flash erase request or receive buffer full, 253 | uSleep(500*1000); // sleep a bit to allow the device to go into usb idle mode. 254 | // This sleep is IMPORTANT : it allows the device to switch 255 | // to usb idle mode where it erases/writes to flash. 256 | 257 | if (buf[0] == 0x40) break; // ??? 258 | 259 | if (addrStart>=addrEnd) 260 | { 261 | if (addrStart<0xff80) 262 | { 263 | // done flashing code segment, now do interrupts 264 | //_____________________ we want the interrupt vector table relocated 265 | addrStart = 0xffa0; 266 | addrEnd = 0xffc0; 267 | memcpy(data+0xffa0-flash_start, data+0xffe0-flash_start, 0x20); 268 | printf("\ninterrupt vector\n"); 269 | instr = 0x10; 270 | bcnt = 0; 271 | }//if 272 | else 273 | { 274 | instr = 0x40; 275 | //addrStart -= 8; 276 | }//else 277 | uSleep(100*1000); 278 | }//if 279 | }//while 280 | 281 | }//if 282 | 283 | }//if 284 | else { 285 | printf("cannot open file %s!\n", argv[1]); 286 | }//else 287 | }//if 288 | if (dev != NULL) usbCloseDevice(dev); 289 | 290 | return 0; 291 | } 292 | 293 | /* ------------------------------------------------------------------------- */ 294 | 295 | 296 | -------------------------------------------------------------------------------- /commandline/usb-libusb.c: -------------------------------------------------------------------------------- 1 | /* Name: usb-libusb.c 2 | * Project: usbcalls library 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2006-02-02 5 | * Tabsize: 4 6 | * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: Proprietary, free under certain conditions. See Documentation. 8 | * This Revision: $Id$ 9 | */ 10 | 11 | /* 12 | General Description: 13 | This module implements USB HID report receiving/sending based on libusb. It 14 | does not read and parse the report descriptor. You must therefore be careful 15 | to pass correctly formatted data blocks of correct size. In order to be 16 | compatible with the Windows implementation, we add a zero report ID for all 17 | reports which don't have an ID. Since we don't parse the descriptor, the caller 18 | must tell us whether report IDs are used or not in usbOpenDevice(). 19 | 20 | The implementation of dummy report IDs is a hack. Whether they are used is 21 | stored in a global variable, not in the device structure (just laziness, don't 22 | want to allocate memory for that). If you open more than one device and the 23 | devices differ in report ID usage, you must change the code. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #define usbDevice usb_dev_handle /* use libusb's device structure */ 31 | #include "usbcalls.h" 32 | 33 | /* ------------------------------------------------------------------------- */ 34 | 35 | #define USBRQ_HID_GET_REPORT 0x01 36 | #define USBRQ_HID_SET_REPORT 0x09 37 | 38 | static int usesReportIDs; 39 | 40 | /* ------------------------------------------------------------------------- */ 41 | 42 | static int usbGetStringAscii(usb_dev_handle *dev, int index, int langid, char *buf, int buflen) 43 | { 44 | char buffer[256]; 45 | int rval, i; 46 | 47 | if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, langid, buffer, sizeof(buffer), 1000)) < 0) 48 | return rval; 49 | if(buffer[1] != USB_DT_STRING) 50 | return 0; 51 | if((unsigned char)buffer[0] < rval) 52 | rval = (unsigned char)buffer[0]; 53 | rval /= 2; 54 | /* lossy conversion to ISO Latin1 */ 55 | for(i=1;i buflen) /* destination buffer overflow */ 57 | break; 58 | buf[i-1] = buffer[2 * i]; 59 | if(buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */ 60 | buf[i-1] = '?'; 61 | } 62 | buf[i-1] = 0; 63 | return i-1; 64 | } 65 | 66 | int usbOpenDevice(usbDevice_t **device, int vendor, char *vendorName, int product, char *productName, int _usesReportIDs) 67 | { 68 | struct usb_bus *bus; 69 | struct usb_device *dev; 70 | usb_dev_handle *handle = NULL; 71 | int errorCode = USB_ERROR_NOTFOUND; 72 | static int didUsbInit = 0; 73 | 74 | if(!didUsbInit){ 75 | usb_init(); 76 | didUsbInit = 1; 77 | } 78 | usb_find_busses(); 79 | usb_find_devices(); 80 | for(bus=usb_get_busses(); bus; bus=bus->next){ 81 | for(dev=bus->devices; dev; dev=dev->next){ 82 | if(dev->descriptor.idVendor == vendor && dev->descriptor.idProduct == product){ 83 | char string[256]; 84 | int len; 85 | handle = usb_open(dev); /* we need to open the device in order to query strings */ 86 | if(!handle){ 87 | errorCode = USB_ERROR_ACCESS; 88 | fprintf(stderr, "Warning: cannot open USB device: %s\n", usb_strerror()); 89 | continue; 90 | } 91 | if(vendorName == NULL && productName == NULL){ /* name does not matter */ 92 | break; 93 | } 94 | /* now check whether the names match: */ 95 | len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, 0x0409, string, sizeof(string)); 96 | if(len < 0){ 97 | errorCode = USB_ERROR_IO; 98 | fprintf(stderr, "Warning: cannot query manufacturer for device: %s\n", usb_strerror()); 99 | }else{ 100 | errorCode = USB_ERROR_NOTFOUND; 101 | /* fprintf(stderr, "seen device from vendor ->%s<-\n", string); */ 102 | if(strcmp(string, vendorName) == 0){ 103 | len = usbGetStringAscii(handle, dev->descriptor.iProduct, 0x0409, string, sizeof(string)); 104 | if(len < 0){ 105 | errorCode = USB_ERROR_IO; 106 | fprintf(stderr, "Warning: cannot query product for device: %s\n", usb_strerror()); 107 | }else{ 108 | errorCode = USB_ERROR_NOTFOUND; 109 | /* fprintf(stderr, "seen product ->%s<-\n", string); */ 110 | if(strcmp(string, productName) == 0) 111 | break; 112 | } 113 | } 114 | } 115 | usb_close(handle); 116 | handle = NULL; 117 | } 118 | } 119 | if(handle) 120 | break; 121 | } 122 | if(handle != NULL){ 123 | int rval, retries = 3; 124 | if(usb_set_configuration(handle, 1)){ 125 | fprintf(stderr, "Warning: could not set configuration: %s\n", usb_strerror()); 126 | } 127 | /* now try to claim the interface and detach the kernel HID driver on 128 | * linux and other operating systems which support the call. 129 | */ 130 | while((rval = usb_claim_interface(handle, 0)) != 0 && retries-- > 0){ 131 | #ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP 132 | if(usb_detach_kernel_driver_np(handle, 0) < 0){ 133 | fprintf(stderr, "Warning: could not detach kernel HID driver: %s\n", usb_strerror()); 134 | } 135 | #endif 136 | } 137 | #ifndef __APPLE__ 138 | if(rval != 0) 139 | fprintf(stderr, "Warning: could not claim interface\n"); 140 | #endif 141 | /* Continue anyway, even if we could not claim the interface. Control transfers 142 | * should still work. 143 | */ 144 | errorCode = 0; 145 | *device = handle; 146 | usesReportIDs = _usesReportIDs; 147 | } 148 | return errorCode; 149 | } 150 | 151 | /* ------------------------------------------------------------------------- */ 152 | 153 | void usbCloseDevice(usbDevice_t *device) 154 | { 155 | if(device != NULL) 156 | usb_close(device); 157 | } 158 | 159 | /* ------------------------------------------------------------------------- */ 160 | 161 | int usbSetReport(usbDevice_t *device, int reportType, char *buffer, int len) 162 | { 163 | int bytesSent; 164 | 165 | if(!usesReportIDs){ 166 | buffer++; /* skip dummy report ID */ 167 | len--; 168 | } 169 | bytesSent = usb_control_msg(device, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_ENDPOINT_OUT, USBRQ_HID_SET_REPORT, reportType << 8 | buffer[0], 0, buffer, len, 5000); 170 | if(bytesSent != len){ 171 | if(bytesSent < 0) 172 | fprintf(stderr, "Error sending message: %s\n", usb_strerror()); 173 | return USB_ERROR_IO; 174 | } 175 | return 0; 176 | } 177 | 178 | /* ------------------------------------------------------------------------- */ 179 | 180 | int usbGetReport(usbDevice_t *device, int reportType, int reportNumber, char *buffer, int *len) 181 | { 182 | int bytesReceived, maxLen = *len; 183 | 184 | if(!usesReportIDs){ 185 | buffer++; /* make room for dummy report ID */ 186 | maxLen--; 187 | } 188 | bytesReceived = usb_control_msg(device, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_ENDPOINT_IN, USBRQ_HID_GET_REPORT, reportType << 8 | reportNumber, 0, buffer, maxLen, 5000); 189 | if(bytesReceived < 0){ 190 | fprintf(stderr, "Error sending message: %s\n", usb_strerror()); 191 | return USB_ERROR_IO; 192 | } 193 | *len = bytesReceived; 194 | if(!usesReportIDs){ 195 | buffer[-1] = reportNumber; /* add dummy report ID */ 196 | *len++; 197 | } 198 | return 0; 199 | } 200 | 201 | /* ------------------------------------------------------------------------- */ 202 | 203 | 204 | -------------------------------------------------------------------------------- /commandline/usb-windows.c: -------------------------------------------------------------------------------- 1 | /* Name: usb-windows.c 2 | * Project: usbcalls library 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2006-02-02 5 | * Tabsize: 4 6 | * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: Proprietary, free under certain conditions. See Documentation. 8 | * This Revision: $Id$ 9 | */ 10 | 11 | /* 12 | General Description: 13 | This module implements USB HID report receiving and sending with native 14 | Windows API functions. If you compile with MinGW, no software from Microsoft 15 | (no DDK) is needed. We supply the missing types and function prototypes in 16 | hidsdi.h. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include "hidsdi.h" 23 | #include 24 | 25 | #include "usbcalls.h" 26 | 27 | #ifdef DEBUG 28 | #define DEBUG_PRINT(arg) printf arg 29 | #else 30 | #define DEBUG_PRINT(arg) 31 | #endif 32 | 33 | /* ------------------------------------------------------------------------ */ 34 | 35 | static void convertUniToAscii(char *buffer) 36 | { 37 | unsigned short *uni = (void *)buffer; 38 | char *ascii = buffer; 39 | 40 | while(*uni != 0){ 41 | if(*uni >= 256){ 42 | *ascii++ = '?'; 43 | }else{ 44 | *ascii++ = *uni++; 45 | } 46 | } 47 | *ascii++ = 0; 48 | } 49 | 50 | int usbOpenDevice(usbDevice_t **device, int vendor, char *vendorName, int product, char *productName, int usesReportIDs) 51 | { 52 | GUID hidGuid; /* GUID for HID driver */ 53 | HDEVINFO deviceInfoList; 54 | SP_DEVICE_INTERFACE_DATA deviceInfo; 55 | SP_DEVICE_INTERFACE_DETAIL_DATA *deviceDetails = NULL; 56 | DWORD size; 57 | int i, openFlag = 0; /* may be FILE_FLAG_OVERLAPPED */ 58 | int errorCode = USB_ERROR_NOTFOUND; 59 | HANDLE handle = INVALID_HANDLE_VALUE; 60 | HIDD_ATTRIBUTES deviceAttributes; 61 | 62 | HidD_GetHidGuid(&hidGuid); 63 | deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE); 64 | deviceInfo.cbSize = sizeof(deviceInfo); 65 | for(i=0;;i++){ 66 | if(handle != INVALID_HANDLE_VALUE){ 67 | CloseHandle(handle); 68 | handle = INVALID_HANDLE_VALUE; 69 | } 70 | if(!SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i, &deviceInfo)) 71 | break; /* no more entries */ 72 | /* first do a dummy call just to determine the actual size required */ 73 | SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, NULL, 0, &size, NULL); 74 | if(deviceDetails != NULL) 75 | free(deviceDetails); 76 | deviceDetails = malloc(size); 77 | deviceDetails->cbSize = sizeof(*deviceDetails); 78 | /* this call is for real: */ 79 | SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, deviceDetails, size, &size, NULL); 80 | DEBUG_PRINT(("checking HID path \"%s\"\n", deviceDetails->DevicePath)); 81 | /* attempt opening for R/W -- we don't care about devices which can't be accessed */ 82 | handle = CreateFile(deviceDetails->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, openFlag, NULL); 83 | if(handle == INVALID_HANDLE_VALUE){ 84 | DEBUG_PRINT(("opening failed: %d\n", (int)GetLastError())); 85 | /* errorCode = USB_ERROR_ACCESS; opening will always fail for mouse -- ignore */ 86 | continue; 87 | } 88 | deviceAttributes.Size = sizeof(deviceAttributes); 89 | HidD_GetAttributes(handle, &deviceAttributes); 90 | DEBUG_PRINT(("device attributes: vid=%d pid=%d\n", deviceAttributes.VendorID, deviceAttributes.ProductID)); 91 | if(deviceAttributes.VendorID != vendor || deviceAttributes.ProductID != product) 92 | continue; /* ignore this device */ 93 | errorCode = USB_ERROR_NOTFOUND; 94 | if(vendorName != NULL && productName != NULL){ 95 | char buffer[512]; 96 | if(!HidD_GetManufacturerString(handle, buffer, sizeof(buffer))){ 97 | DEBUG_PRINT(("error obtaining vendor name\n")); 98 | errorCode = USB_ERROR_IO; 99 | continue; 100 | } 101 | convertUniToAscii(buffer); 102 | DEBUG_PRINT(("vendorName = \"%s\"\n", buffer)); 103 | if(strcmp(vendorName, buffer) != 0) 104 | continue; 105 | if(!HidD_GetProductString(handle, buffer, sizeof(buffer))){ 106 | DEBUG_PRINT(("error obtaining product name\n")); 107 | errorCode = USB_ERROR_IO; 108 | continue; 109 | } 110 | convertUniToAscii(buffer); 111 | DEBUG_PRINT(("productName = \"%s\"\n", buffer)); 112 | if(strcmp(productName, buffer) != 0) 113 | continue; 114 | } 115 | break; /* we have found the device we are looking for! */ 116 | } 117 | SetupDiDestroyDeviceInfoList(deviceInfoList); 118 | if(deviceDetails != NULL) 119 | free(deviceDetails); 120 | if(handle != INVALID_HANDLE_VALUE){ 121 | *device = (usbDevice_t *)handle; 122 | errorCode = 0; 123 | } 124 | return errorCode; 125 | } 126 | 127 | /* ------------------------------------------------------------------------ */ 128 | 129 | void usbCloseDevice(usbDevice_t *device) 130 | { 131 | CloseHandle((HANDLE)device); 132 | } 133 | 134 | /* ------------------------------------------------------------------------ */ 135 | 136 | int usbSetReport(usbDevice_t *device, int reportType, char *buffer, int len) 137 | { 138 | HANDLE handle = (HANDLE)device; 139 | BOOLEAN rval = 0; 140 | DWORD bytesWritten; 141 | 142 | switch(reportType){ 143 | case USB_HID_REPORT_TYPE_INPUT: 144 | break; 145 | case USB_HID_REPORT_TYPE_OUTPUT: 146 | rval = WriteFile(handle, buffer, len, &bytesWritten, NULL); 147 | break; 148 | case USB_HID_REPORT_TYPE_FEATURE: 149 | rval = HidD_SetFeature(handle, buffer, len); 150 | break; 151 | } 152 | return rval == 0 ? USB_ERROR_IO : 0; 153 | } 154 | 155 | /* ------------------------------------------------------------------------ */ 156 | 157 | int usbGetReport(usbDevice_t *device, int reportType, int reportNumber, char *buffer, int *len) 158 | { 159 | HANDLE handle = (HANDLE)device; 160 | BOOLEAN rval = 0; 161 | DWORD bytesRead; 162 | 163 | switch(reportType){ 164 | case USB_HID_REPORT_TYPE_INPUT: 165 | buffer[0] = reportNumber; 166 | rval = ReadFile(handle, buffer, *len, &bytesRead, NULL); 167 | if(rval) 168 | *len = bytesRead; 169 | break; 170 | case USB_HID_REPORT_TYPE_OUTPUT: 171 | break; 172 | case USB_HID_REPORT_TYPE_FEATURE: 173 | buffer[0] = reportNumber; 174 | rval = HidD_GetFeature(handle, buffer, *len); 175 | break; 176 | } 177 | return rval == 0 ? USB_ERROR_IO : 0; 178 | } 179 | 180 | /* ------------------------------------------------------------------------ */ 181 | -------------------------------------------------------------------------------- /commandline/usbcalls.c: -------------------------------------------------------------------------------- 1 | /* Name: usbcalls.c 2 | * Project: usbcalls library 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2006-02-02 5 | * Tabsize: 4 6 | * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: Proprietary, free under certain conditions. See Documentation. 8 | * This Revision: $Id$ 9 | */ 10 | 11 | /* This file includes the appropriate implementation based on platform 12 | * specific defines. 13 | */ 14 | 15 | #if defined(WIN32) 16 | # include "usb-windows.c" 17 | void uSleep(__int64 usec) 18 | { 19 | HANDLE timer; 20 | LARGE_INTEGER ft; 21 | 22 | ft.QuadPart = -(10*usec); // Convert to 100 nanosecond interval, negative value indicates relative time 23 | 24 | timer = CreateWaitableTimer(NULL, TRUE, NULL); 25 | SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0); 26 | WaitForSingleObject(timer, INFINITE); 27 | CloseHandle(timer); 28 | } 29 | #else 30 | /* e.g. defined(__APPLE__) */ 31 | # include "usb-libusb.c" 32 | #endif 33 | -------------------------------------------------------------------------------- /commandline/usbcalls.h: -------------------------------------------------------------------------------- 1 | /* Name: usbcalls.h 2 | * Project: usbcalls library 3 | * Author: Christian Starkjohann 4 | * Creation Date: 2006-02-02 5 | * Tabsize: 4 6 | * Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH 7 | * License: Proprietary, free under certain conditions. See Documentation. 8 | * This Revision: $Id$ 9 | */ 10 | 11 | #ifndef __usbcalls_h_INCLUDED__ 12 | #define __usbcalls_h_INCLUDED__ 13 | 14 | /* 15 | General Description: 16 | This module implements an abstraction layer for access to USB/HID communication 17 | functions. An implementation based on libusb (portable to Linux, FreeBSD and 18 | Mac OS X) and a native implementation for Windows are provided. 19 | */ 20 | 21 | /* ------------------------------------------------------------------------ */ 22 | 23 | #define USB_HID_REPORT_TYPE_INPUT 1 24 | #define USB_HID_REPORT_TYPE_OUTPUT 2 25 | #define USB_HID_REPORT_TYPE_FEATURE 3 26 | /* Numeric constants for 'reportType' parameters */ 27 | 28 | #define USB_ERROR_NONE 0 29 | #define USB_ERROR_ACCESS 1 30 | #define USB_ERROR_NOTFOUND 2 31 | #define USB_ERROR_BUSY 16 32 | #define USB_ERROR_IO 5 33 | /* These are the error codes which can be returned by functions of this 34 | * module. 35 | */ 36 | 37 | /* ------------------------------------------------------------------------ */ 38 | 39 | typedef struct usbDevice usbDevice_t; 40 | /* This type represents a USB device internally. Only opaque pointers to this 41 | * type are available outside the module implementation. 42 | */ 43 | 44 | /* ------------------------------------------------------------------------ */ 45 | 46 | int usbOpenDevice(usbDevice_t **device, int vendor, char *vendorName, int product, char *productName, int usesReportIDs); 47 | /* This function opens a USB device. 'vendor' and 'product' are the numeric 48 | * Vendor-ID and Product-ID of the device we want to open. If 'vendorName' and 49 | * 'productName' are both not NULL, only devices with matching manufacturer- 50 | * and product name strings are accepted. If the device uses report IDs, 51 | * 'usesReportIDs' must be set to a non-zero value. 52 | * Returns: If a matching device has been found, USB_ERROR_NONE is returned and 53 | * '*device' is set to an opaque pointer representing the device. The device 54 | * must be closed with usbCloseDevice(). If the device has not been found or 55 | * opening failed, an error code is returned. 56 | */ 57 | void usbCloseDevice(usbDevice_t *device); 58 | /* Every device opened with usbOpenDevice() must be closed with this function. 59 | */ 60 | int usbSetReport(usbDevice_t *device, int reportType, char *buffer, int len); 61 | /* This function sends a report to the device. 'reportType' specifies the type 62 | * of report (see USB_HID_REPORT_TYPE* constants). The report ID must be in the 63 | * first byte of buffer and the length 'len' of the report is specified 64 | * including this report ID. If no report IDs are used, buffer[0] must be set 65 | * to 0 (dummy report ID). 66 | * Returns: 0 on success, an error code otherwise. 67 | */ 68 | int usbGetReport(usbDevice_t *device, int reportType, int reportID, char *buffer, int *len); 69 | /* This function obtains a report from the device. 'reportType' specifies the 70 | * type of report (see USB_HID_REPORT_TYPE* constants). The requested report ID 71 | * is passed in 'reportID'. The caller must pass a buffer of the size of the 72 | * expected report in 'buffer' and initialize the variable in '*len' to the 73 | * total size of this buffer. Upon successful return, the report (prefixed with 74 | * a report ID) is in 'buffer' and the actual length of the report is returned 75 | * in '*len'. 76 | * Returns: 0 on success, an error code otherwise. 77 | */ 78 | 79 | /* ------------------------------------------------------------------------ */ 80 | 81 | #if defined(WIN32) 82 | #include 83 | void uSleep(__int64 usec); 84 | #else 85 | #define uSleep usleep 86 | #endif 87 | 88 | /* ------------------------------------------------------------------------ */ 89 | 90 | #endif /* __usbcalls_h_INCLUDED__ */ 91 | -------------------------------------------------------------------------------- /hid430.c: -------------------------------------------------------------------------------- 1 | // 2 | // HID Mouse example 3 | // 4 | // Copyright © 2012 Kevin Timmerman 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | 20 | /* 21 | 22 | Schematics 23 | Note: decoupling CAP and LDO are not shown 24 | 25 | 26 | // VCC (3.3V) 27 | // | 28 | // +------+ MSP430G2452/ 29 | // _ _ MSP430G2553 30 | // |1| |4| --------------- 31 | // |K| |K| | XIN|--+ 32 | // |5| |7| | | [ ] 32.768KHz XTAL (optional) 33 | // - - | XOUT|--+ 34 | // | | | | __o__ 35 | // | +---|RST P2.0|--o o---o LEFT \ 36 | // | | | __o__ | | 37 | // +----------|P1.1 P2.1|--o o---o UP | 38 | // | | | __o__ | | 39 | // | +---|P1.0 P2.2|--o o---o LEFT CLICK > Mouse controls 40 | // _ _ | | __o__ | | 41 | // |6| |6| | P2.3|--o o---o RIGHT | 42 | // |8| |8| | | __o__ | | 43 | // |R| |R| | P2.4|--o o---o DOWN / 44 | // - - _|_ 45 | // | | /// 46 | // USB D- D+ 47 | // 48 | // 49 | 50 | */ 51 | 52 | 53 | #include 54 | #include "bbusb.h" 55 | 56 | 57 | 58 | static unsigned FrequencyCounter; 59 | static uint8_t IrqInSendPacketBuffer[12]; 60 | static const uint8_t usb_packet_stall[] = { 61 | 1, USB_PID_STALL 62 | }; 63 | 64 | 65 | uint8_t TokenPacketBuffer[16]; 66 | uint8_t DataPacketBuffer[16] = { 0 }; 67 | uint8_t *ReadyForTransmitIrqIn = 0; 68 | unsigned CurrentAddress = 0; 69 | unsigned NewAddress = 0; 70 | unsigned Data_PID_ToggleIrqIn = USB_PID_DATA1; 71 | uint8_t *ReceiveBufferPointer = TokenPacketBuffer; 72 | 73 | 74 | extern unsigned Data_PID_Toggle; 75 | extern unsigned DataToTransmitOffset; 76 | extern const uint8_t *DataToTransmit; 77 | extern const uint8_t *ReadyForTransmit; 78 | 79 | 80 | 81 | uint8_t mouse_btn_clicked = 0; 82 | uint8_t centerClicked(){ 83 | if((P2IN & BIT2) == 0){ 84 | if(!mouse_btn_clicked){ 85 | mouse_btn_clicked = 1; 86 | return 1; 87 | } 88 | } else { 89 | if(mouse_btn_clicked){ 90 | mouse_btn_clicked = 0; 91 | return 0; 92 | } 93 | } 94 | return 0; 95 | } 96 | 97 | uint8_t horizClicked(){ 98 | if((P2IN & BIT0) == 0){ 99 | return -1; 100 | } 101 | if((P2IN & BIT3) == 0){ 102 | return 1; 103 | } 104 | return 0; 105 | } 106 | 107 | 108 | uint8_t vertClicked(){ 109 | if((P2IN & BIT1) == 0){ 110 | return -1; 111 | } 112 | if((P2IN & BIT4) == 0){ 113 | return 1; 114 | } 115 | return 0; 116 | } 117 | 118 | void MouseIrqIn(uint8_t *d) // 119 | { // -- Mouse HID response 120 | *d++ = 5; // Length 121 | // Data PID toggle 122 | *d++ = (Data_PID_ToggleIrqIn ^= (USB_PID_DATA0 ^ USB_PID_DATA1)); 123 | *d++ = centerClicked(); // Buttons 124 | *d++ = horizClicked(); // X 125 | *d++ = vertClicked(); // Y 126 | *d++ = 0; // Wheel 127 | } 128 | 129 | 130 | void main(void) 131 | { 132 | WDTCTL = WDTPW | WDTHOLD; // Stop watchdog 133 | // 134 | P1OUT = 0; // Prepare Port 1 135 | usbdir = ~(usbplus | usbminus); // USB lines are inputs 136 | //P1SEL |= BIT4; // SMCLK for measurements on P1.4 137 | 138 | // ABP: mouse 139 | // Input Pull-up 140 | P2OUT = 0; 141 | P2SEL &= ~(BIT0 | BIT1 | BIT2 | BIT3 | BIT4); 142 | P2DIR &= ~(BIT0 | BIT1 | BIT2 | BIT3 | BIT4); 143 | P2REN |= BIT0 | BIT1 | BIT2 | BIT3 | BIT4; 144 | P2OUT |= BIT0 | BIT1 | BIT2 | BIT3 | BIT4; 145 | 146 | // 147 | FrequencyCounter = 0; // 148 | // 149 | #ifdef USE_32768HZ_XTAL 150 | BCSCTL1 = DIVA_3 | 15; // ACLK / 8, Range 15 151 | #else 152 | BCSCTL1 = 15; // Range 15 153 | #endif 154 | DCOCTL = 127; // ~15 MHz 155 | // 156 | TACTL = TASSEL_2 | MC_2 | TACLR; // Continous up mode with clocking from SMCLK 157 | #ifdef USE_32768HZ_XTAL 158 | TACCTL0 = CM_1 | CCIS_1 | CAP | CCIE; // Prepare CCR0 for capturing on rising edges of ACLK with enabled interrupts 159 | #endif 160 | // 161 | //_enable_interrupts(); // Begin DCO clock tuning 162 | _BIS_SR(GIE); 163 | 164 | 165 | #ifndef USE_32768HZ_XTAL 166 | uint8_t wait=32; 167 | while (--wait) 168 | #endif 169 | __delay_cycles(1000000); // Allow some time to stabilize 170 | // 171 | // 172 | usbies = 0; // Interrupt on rising edge of D+ because there is keep-alive signaling on 173 | // D- that would cause false syncs 174 | usbifg = 0; // No interrupt pending 175 | #ifdef USE_32768HZ_XTAL 176 | usbie = usbplus; // Interrupt enable for D+ 177 | #endif 178 | // 179 | for(;;) { // for-ever 180 | unsigned n = 80; // Reset if both D+ and D- stay low for a while 181 | // 10 ms in SE0 is reset 182 | // Should this be done in the ISR somehow??? 183 | while(!(usbin & (usbplus | usbminus))) { 184 | if(!--n) { // 185 | CurrentAddress = 0; // Device has initial address of 0 186 | NewAddress = 0; // 187 | #ifndef USE_32768HZ_XTAL 188 | if (!wait) { 189 | wait = 1; 190 | while (!(usbin&usbminus)); 191 | while ((usbin&usbminus)); 192 | 193 | 194 | n = 1000; 195 | while (--n) { 196 | while (!(usbin&usbminus)); 197 | TACTL |= TACLR; 198 | while ((usbin&usbminus)); 199 | 200 | 201 | if (TAR < 15000) ++DCOCTL; 202 | else --DCOCTL; 203 | }//while 204 | 205 | 206 | P1OUT |= BIT2; 207 | usbie = usbplus; 208 | }//if 209 | #endif 210 | break; // 211 | } // 212 | } // 213 | if(DataPacketBuffer[0]) { // Check if the USB SIE has received a packet 214 | // At the end of the buffer is the PID of the preceding token packet 215 | // Check if it is a SETUP packet 216 | if(DataPacketBuffer[15] == USB_PID_SETUP) { 217 | // Handle the packet, get a response 218 | if(DataToTransmit = ProtocolSetupPacket(DataPacketBuffer)) { 219 | // Setup to send the response 220 | Data_PID_Toggle = USB_PID_DATA0; 221 | DataToTransmitOffset = 1; 222 | } else { // 223 | // Send STALL PID if there is no response 224 | ReadyForTransmit = usb_packet_stall; 225 | } // 226 | // Check if it is an OUT packet 227 | } else if(DataPacketBuffer[15] == USB_PID_OUT) { 228 | } // 229 | DataPacketBuffer[0] = 0; // Done with received packet, don't process again, allow USB SIE 230 | // to receive the next packet 231 | } // 232 | // Check if an outgoing packet needs chunking and the USB SIE 233 | // is ready for it 234 | if(DataToTransmit && !ReadyForTransmit) { 235 | PacketGenerator(); // Make a chunk with CRC 236 | } // 237 | // 238 | if(!ReadyForTransmitIrqIn) { // Check if the USB SIE is ready for an endpoint 1 packet 239 | MouseIrqIn(IrqInSendPacketBuffer); // Build the packet 240 | CRC(IrqInSendPacketBuffer); // Append CRC 241 | // Send it 242 | ReadyForTransmitIrqIn = IrqInSendPacketBuffer; 243 | } // 244 | } // 245 | } 246 | 247 | 248 | 249 | 250 | #ifdef USE_32768HZ_XTAL 251 | #pragma vector = TIMER0_A0_VECTOR // Timer A CCR0 interrupt 252 | __interrupt void dco_adjust(void) // 253 | { // 254 | TA0CCTL0 &= ~CCIFG; // Clear interrupt flag 255 | //_enable_interrupts(); // Re-enable interrupts to allow fast response to USB 256 | _BIS_SR(GIE); 257 | // Adjust DCO 258 | // 15,000,000 / (32,768 / 8) = 3662.11 259 | // 3662.5 * (32,768 / 8) = 15,001,600 260 | if((TA0CCR0 - FrequencyCounter) < 3662) ++DCOCTL; else --DCOCTL; 261 | FrequencyCounter = TA0CCR0; // 262 | } // 263 | #endif 264 | 265 | -------------------------------------------------------------------------------- /hid430.hex: -------------------------------------------------------------------------------- 1 | :10F000005542200135D0085A82454C023140000457 2 | :10F010003F4006000F93082492424C0220012F83A8 3 | :10F020009F4F5CF70002F8233F4046000F930724F0 4 | :10F0300092424C0220011F83CF430602F923B240C3 5 | :10F04000805A2001C2432100F240FCFF220082438B 6 | :10F050001C02F2400F005700F2407F005600B24001 7 | :10F060002402600132D27D402000083C3E40060070 8 | :10F070003F400E161F83FE231E83FC237D53F62381 9 | :10F08000C2432400C24323004B433F4028002F3C8F 10 | :10F090003F532D2082430802824306024B932C20CB 11 | :10F0A0005F4220002FF3FC275F4220002FF3FC2358 12 | :10F0B0003F40FA00143C5E4220002EF3FC27A2D20F 13 | :10F0C00060015E4220002EF3FC231E4270013E9040 14 | :10F0D000983A032CD2535600023CF25356003F5349 15 | :10F0E000EA23E2D22100D24325005B43053C5E4285 16 | :10F0F00020003EF00300CC27C2930C021724F290AC 17 | :10F100002D001B0211203F400C02B01238F2824F3A 18 | :10F110002A020F930624B240C300040292434A021B 19 | :10F12000033CB2409EF62C02C2430C0282932A0298 20 | :10F13000052482932C020220B012DCF182930A0291 21 | :10F14000A4233F401E02B012EAF23F401E02B0125A 22 | :10F1500064F1B2401E020A02983F32D0F000FD3F37 23 | :10F1600030409CF60B126E4F4C4E0C5F6E53CF4EE0 24 | :10F1700000002F533E43283C7D4F0DEE8E104E4E27 25 | :10F180001DB302243EE0C1C02DB302243EE081C184 26 | :10F190002DB202243EE001C33DB202243EE001C68E 27 | :10F1A0003DB0100002243EE001CC3DB0200002241E 28 | :10F1B0003EE001D83DB0400002243EE001F03DF0C9 29 | :10F1C000800002243EE001A00C9FD62F3EE3CF4EEC 30 | :10F1D00000008E10CF4E01003B4130410B121F4208 31 | :10F1E0002A021B424A020E4F0E5B6C4F0C5F1F42FD 32 | :10F1F00004023FE08800824F0402C24F2F020F43F7 33 | :10F200003D4030020C9E032C82432A02063CFD4EF8 34 | :10F2100000001D531F533F92F5230B5F824B4A02A0 35 | :10F220005F53C24F2E023F402E02B01264F1B24033 36 | :10F230002E022C023B4130415E4F02003EF0200086 37 | :10F240000524FF900A0003004520463CFF900C0077 38 | :10F250000300402C5E4F03000E5E104EA0F63F40B0 39 | :10F26000B9F63041D24F04000602C2430702343CD3 40 | :10F270005E4F05006E9310247E900300032C5E9376 41 | :10F280002B20073C7E9003000E247E902200242039 42 | :10F29000183C3F40BCF63041FF90090008001F2099 43 | :10F2A0003F40CFF630415F4F04005F931B2403289B 44 | :10F2B0006F930720033C3F40FCF630413F4012F77C 45 | :10F2C00030413F4027F7304182430A02B2404B00B1 46 | :10F2D0000202023C0F4330413F40B8F630413F400C 47 | :10F2E000D9F630413F4001F73041FF4005000000B2 48 | :10F2F0001E4202023EE08800824E0202CF4E010012 49 | :10F30000CF430200DF430300CF430400CF43050097 50 | :10F310003041080206022C020A020C0200023A02E4 51 | :10F32000C4F501D2015A011E3C413B413A413941E9 52 | :10F33000D2C323000013F2900F00570002241042A2 53 | :10F34000A4FF09120A12394020002A436AB9042492 54 | :10F350006AB902246AB9EA236AB906206AB90420A4 55 | :10F360006AB902206AB9E2270B126A496B492AB3CB 56 | :10F3700002282BB30128003C0C1203436A492AB32C 57 | :10F380001A28003C6A496B492AB302282BB301288A 58 | :10F39000003C003C003C6A492AB30D28003C6A4905 59 | :10F3A0006B492AB302282BB30128003C003C003CE7 60 | :10F3B0006A492AB3B92F003C003C003C6A493C40F2 61 | :10F3C0007F002AF34C100D120D436B490AEB2AF310 62 | :10F3D0004C100E123E4000026A490BEA2BF34C100F 63 | :10F3E0000F122F4E6B490AEB2AF34C1008123840CB 64 | :10F3F000FC006A490BEA2BF34C10413C6A490BEACA 65 | :10F400002BF34C100D433EE30CB807206A493AF049 66 | :10F4100003006D243CD080001DE36B493BF00300EA 67 | :10F4200066240AEB2AF34C100CB86A4908200B4AF0 68 | :10F4300003433CD080002DE303436A49003C0BEAC0 69 | :10F440002BF34C100CB807206A493AF003004F2404 70 | :10F450003CD080002DE26B490AEB2AF34C10CF4ED2 71 | :10F4600000000CB86A4908200B4A03433CD08000D6 72 | :10F470003DE203436A49003C0BEA2BF34C100CB805 73 | :10F4800008206A493AF0030032243CD080003DE075 74 | :10F4900010006B490AEB2AF34C101F5303430CB8BE 75 | :10F4A00008206B493BF0030022243CD080003DE063 76 | :10F4B00020006A490BEA2BF34C10003C0CB80820E2 77 | :10F4C0006A493AF0030013243CD080003DE040003C 78 | :10F4D0006B490AEB2AF34C100E4C0ECD0CB88E2360 79 | :10F4E0006B492BF33CD080000343003C873FD2C3E1 80 | :10F4F0002300CF4E00001E4200020F8ECE4F0000B0 81 | :10F50000003C003C5A4E01005B4E02005C4E030082 82 | :10F510003BB080000C6C3CF00F003BC080003A9088 83 | :10F52000690022243A90E1003F243A902D003C24C7 84 | :10F53000B2900C0200020920B2403A0200023A9056 85 | :10F54000C3003B243A904B00382438413F413E41B0 86 | :10F550003D413C413B41D2B32300F52E3A41394174 87 | :10F56000D2B32300EE2E0013C29B0802EE231C939D 88 | :10F5700005201F420A0282430A02043C1F422C0259 89 | :10F5800082432C020F9304203F4024F33040C4F503 90 | :10F590008F93000005249242060208023040C4F511 91 | :10F5A0003F4026F33040C4F5C29B0802CE23C24A36 92 | :10F5B0001B02B2400C020002C83F3F4022F3304021 93 | :10F5C000C4F50013D2C32100E2D321003940030067 94 | :10F5D000C2D922007A4F1A533B4080000C430B11D2 95 | :10F5E00006281C833C90FBFF052C0343F93FC2E92E 96 | :10F5F00021000C4308430B11034305281C833C9056 97 | :10F60000FBFF042CF93FC2E921000C430B1103431B 98 | :10F6100005281C833C90FBFF042CF93F0C43C2E9F6 99 | :10F62000210018E3E8230B11034305281C833C90B9 100 | :10F63000FBFF042CF93FC2E921000C437D4F0B1165 101 | :10F6400006281C833C90FBFF052C0343F93FC2E9CD 102 | :10F6500021000C430B110B4D05281C833C90FBFF34 103 | :10F66000042CF93F0C43C2E921001A83B823003C63 104 | :10F67000F2C00300210038413F413E413D413C4141 105 | :10F680003B413A413941E2D32100003C003C034375 106 | :0EF69000F2C003002200D2C3230000130013B7 107 | :10F69E00011E5EF2D4F2D4F2D4F2D4F264F270F21D 108 | :10F6AE00D4F2D4F2D8F2D4F2C8F200020000121250 109 | :10F6BE0001100100000008341201000100010200D7 110 | :10F6CE0001090902220001010080322209022200F2 111 | :10F6DE00010100803209040000010301020009212A 112 | :10F6EE00100100012234000705810305000A0404FD 113 | :10F6FE000309041010036F0050006F0073007300B5 114 | :10F70E0075006D001414034D006F007500730065D5 115 | :10F71E000020003400330030003405010902A1013D 116 | :10F72E000901A100050919012903150025019503F9 117 | :10F73E0075018102950175058103050109300931B5 118 | :0EF74E0009381581257F950375088106C0C016 119 | :06F75C003A024B00C3005D 120 | :10FFE000C2F5C2F536F3C2F5C2F5C2F5C2F5C2F5E7 121 | :10FFF000C2F5C2F5C2F5C2F5C2F5C2F5C2F500F010 122 | :040000030000F00009 123 | :00000001FF 124 | --------------------------------------------------------------------------------