├── .gitignore ├── COPYING ├── Makefile ├── README.md ├── byte_utils.c ├── byte_utils.h ├── error.h ├── ihex.c ├── ihex.h ├── main.c ├── pgm.h ├── spi.c ├── spi.h ├── stlink.c ├── stlink.h ├── stlinkv2.c ├── stlinkv2.h ├── stm8.c ├── stm8.h ├── try.h ├── usb.c ├── usb.h └── utils.h /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | *.o 3 | *.bin 4 | *.ihx 5 | *.hex 6 | *.exe 7 | tags 8 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | ENABLE_USB=1 3 | ENABLE_SPI=1 4 | CFLAGS = -g -O3 --std=gnu99 --pedantic 5 | OBJECTS=main.o byte_utils.o ihex.o stm8.o 6 | 7 | ifeq ($(ENABLE_SPI),1) 8 | OBJECTS+=spi.o 9 | CFLAGS+=-DENABLE_SPI 10 | endif 11 | ifeq ($(ENABLE_USB),1) 12 | OBJECTS+=usb.o stlink.o stlinkv2.o 13 | CFLAGS+=-DENABLE_USB `pkg-config --cflags libusb-1.0` 14 | LIBS+= `pkg-config --libs libusb-1.0` 15 | endif 16 | 17 | PLATFORM=$(shell uname -s) 18 | ifeq ($(PLATFORM),Darwin) 19 | MacOSSDK=`xcrun --show-sdk-path` 20 | CFLAGS += -I$(MacOSSDK)/usr/include/ -I$(MacOSSDK)/usr/include/sys -I$(MacOSSDK)/usr/include/machine 21 | endif 22 | BIN = stm8flash 23 | 24 | all: $(OBJECTS) 25 | $(CC) $(OBJECTS) $(LIBS) -o $(BIN) 26 | 27 | clean: 28 | -rm -f $(OBJECTS) $(BIN) 29 | 30 | install: 31 | cp $(BIN) $(DESTDIR)/usr/bin/ 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | stm8flash 2 | ========= 3 | 4 | This is a free and opensource software distributed under the terms of GNU General Public License v2. 5 | 6 | It also seems to be the only program that's able to communicate through the SWIM interface of ST-LINKs under Linux as for March, 2014. 7 | 8 | 9 | Synopsis 10 | -------- 11 | 12 | ``` 13 | stm8flash -c -p [-s flash|eeprom|0x8000] [-r|-w|-v] 14 | ``` 15 | 16 | Flash examples: 17 | ```nohighlight 18 | ./stm8flash -c stlink -p stm8s003f3 -w blinky.bin 19 | ./stm8flash -c stlink -p stm8s003f3 -w blinky.ihx 20 | ./stm8flash -c stlinkv2 -p stm8s003f3 -w blinky.ihx 21 | ./stm8flash -c stlink -p stm8s105c6 -w blinky.bin 22 | ./stm8flash -c stlinkv2 -p stm8l150 -w blinky.bin 23 | ``` 24 | 25 | EEPROM examples: 26 | ```nohighlight 27 | ./stm8flash -c stlinkv2 -p stm8s003f3 -s eeprom -r ee.bin 28 | ./stm8flash -c stlinkv2 -p stm8s003f3 -s eeprom -w ee.bin 29 | ./stm8flash -c stlinkv2 -p stm8s003f3 -s eeprom -v ee.bin 30 | ``` 31 | 32 | Support table 33 | ------------- 34 | 35 | * ST-Link V1: flash/eeprom/opt 36 | * ST-Link V2: flash2/eeprom2/opt2 37 | 38 | | MCU | flash | eeprom | opt | flash2 | eeprom2 | opt2 | 39 | |-------------|-------|--------|------|--------|---------|-------| 40 | | stlux???a | ? | ? | ? | ? | ? | ? | 41 | | stm8af526? | ? | ? | ? | ? | ? | ? | 42 | | stm8af528? | ? | ? | ? | 32 | ? | ? | 43 | | stm8af52a? | ? | ? | ? | ? | ? | ? | 44 | | stm8af6213 | ? | ? | ? | ? | ? | ? | 45 | | stm8af6223 | ? | ? | ? | ? | ? | ? | 46 | | stm8af6223a | ? | ? | ? | ? | ? | ? | 47 | | stm8af6226 | ? | ? | ? | ? | ? | ? | 48 | | stm8af624? | ? | ? | ? | ? | ? | ? | 49 | | stm8af6266 | ? | ? | ? | ? | ? | ? | 50 | | stm8af6268 | ? | ? | ? | ? | ? | ? | 51 | | stm8af6269 | ? | ? | ? | ? | ? | ? | 52 | | stm8af628? | ? | ? | ? | ? | ? | ? | 53 | | stm8af62a? | ? | ? | ? | ? | ? | ? | 54 | | stm8al313? | ? | ? | ? | ? | ? | ? | 55 | | stm8al314? | ? | ? | ? | ? | ? | ? | 56 | | stm8al316? | ? | ? | ? | ? | ? | ? | 57 | | stm8al3l4? | ? | ? | ? | ? | ? | ? | 58 | | stm8al3l6? | ? | ? | ? | ok | ? | ? | 59 | | stm8l051f3 | ok | ? | ? | ? | ? | ? | 60 | | stm8l052c6 | ok | ? | ? | ? | ? | ? | 61 | | stm8l052r8 | ok | ? | ? | ? | ? | ? | 62 | | stm8l101f1 | ? | no | ? | ? | no | ? | 63 | | stm8l101?2 | ? | no | ? | ? | no | ? | 64 | | stm8l101?3 | ? | no | ? | ok | no | ? | 65 | | stm8l151?2 | ? | ? | ? | ? | ? | ? | 66 | | stm8l151?3 | ? | ? | ? | ? | ? | ? | 67 | | stm8l151?4 | ? | ? | ? | ? | ? | ? | 68 | | stm8l151?6 | ? | ? | ? | ? | ? | ? | 69 | | stm8l151?8 | ? | ? | ? | ? | ? | ? | 70 | | stm8l152?4 | ? | ? | ? | ? | ? | ? | 71 | | stm8l152?6 | ok | FAIL | ? | ok | ok | ? | 72 | | stm8l152?8 | ? | ? | ? | ? | ? | ? | 73 | | stm8l162?8 | ? | ? | ? | ? | ? | ? | 74 | | stm8s003?3 | ok | FAIL | ? | ok | ok | ? | 75 | | stm8s005?6 | ok | ? | ok | ? | ? | ? | 76 | | stm8s007c8 | ? | ? | ? | ? | ? | ? | 77 | | stm8s103f2 | ? | ? | ? | ? | ? | ? | 78 | | stm8s103?3 | ? | ? | ? | ok | ? | ? | 79 | | stm8s105?4 | ok | FAIL | ? | ok | ok | ? | 80 | | stm8s105?6 | ok | ? | ? | ok | ? | ? | 81 | | stm8s207c8 | ? | ? | ? | ? | ? | ? | 82 | | stm8s207cb | ? | ? | ? | ? | ? | ? | 83 | | stm8s207k8 | ? | ? | ? | ? | ? | ? | 84 | | stm8s207m8 | ? | ? | ? | ? | ? | ? | 85 | | stm8s207mb | ? | ? | ? | ? | ? | ? | 86 | | stm8s207r8 | ? | ? | ? | ? | ? | ? | 87 | | stm8s207rb | ? | ? | ? | ? | ? | ? | 88 | | stm8s207s8 | ? | ? | ? | 32 | ? | ? | 89 | | stm8s207sb | ? | ? | ? | ? | ? | ? | 90 | | stm8s207?6 | ? | ? | ? | ? | ? | ? | 91 | | stm8s208c6 | ? | ? | ? | ok | ? | ? | 92 | | stm8s208s6 | ? | ? | ? | ? | ? | ? | 93 | | stm8s208?8 | ? | ? | ? | ? | ? | ? | 94 | | stm8s208?b | ? | ? | ? | 32 | ? | ? | 95 | | stm8s903?3 | ? | ? | ? | ? | ? | ? | 96 | | stm8splnb1 | ? | ? | ? | ? | ? | ? | 97 | | stm8tl5??4 | ? | no | ? | ? | no | ? | 98 | | stnrg???a | ? | ? | ? | ? | ? | ? | 99 | 100 | Legend: 101 | 102 | * `ok` - Fully supported. 103 | * `no` - Not supported. 104 | * `?` - Not tested. 105 | * `FÁIL` - Not working. Needs fix. 106 | * `32` - Lower 32K of flash works, upper doesn't. 107 | 108 | -------------------------------------------------------------------------------- /byte_utils.c: -------------------------------------------------------------------------------- 1 | #include "byte_utils.h" 2 | 3 | void format_int(unsigned char *out, unsigned int in, unsigned char length, unsigned char endianess) { 4 | int i, idx; 5 | for(i = 0; i < length; i++) { 6 | idx = endianess == MP_LITTLE_ENDIAN ? i : length - 1 - i; 7 | out[i] = (in & 0xFF << idx*8) >> idx*8; 8 | } 9 | } 10 | 11 | int load_int(unsigned char *buf, unsigned char length, unsigned char endianess) { 12 | int i, idx, result = 0; 13 | for(i = 0; i < length; i++) { 14 | idx = endianess == MP_LITTLE_ENDIAN ? i : length - 1 - i; 15 | result |= (buf[i] << idx*8); 16 | } 17 | return(result); 18 | } 19 | -------------------------------------------------------------------------------- /byte_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __BYTE_UTILS_H 2 | #define __BYTE_UTILS_H 3 | 4 | #define MP_LITTLE_ENDIAN 0 5 | #define MP_BIG_ENDIAN 1 6 | 7 | #define HI(x) (((x) & 0xff00) >> 8) 8 | #define LO(x) ((x) & 0xff) 9 | 10 | void format_int(unsigned char *out, unsigned int in, unsigned char length, unsigned char endianess); 11 | int load_int(unsigned char *buf, unsigned char length, unsigned char endianess); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /error.h: -------------------------------------------------------------------------------- 1 | #define ERROR(s) do { fprintf(stderr, "%s\n", (s)); exit(-1); } while(0) 2 | #define ERROR2(...) do { fprintf(stderr, __VA_ARGS__); exit(-1); } while(0) 3 | #define PERROR(s) do { perror((s)); exit(-1); } while(0) 4 | #define USAGE_ERROR(s) do { fprintf(stderr, "%s\n", (s)); print_help_and_exit(argv[0]); } while(0) 5 | -------------------------------------------------------------------------------- /ihex.c: -------------------------------------------------------------------------------- 1 | /* stlink/v2 stm8 memory programming utility 2 | (c) Valentin Dudouyt, 2012 - 2014 */ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "ihex.h" 8 | #include "error.h" 9 | #include "byte_utils.h" 10 | 11 | char line[256]; 12 | 13 | static unsigned char checksum(char *buf, unsigned int length, int chunk_len, int chunk_addr, int chunk_type) { 14 | int sum = chunk_len + (LO(chunk_addr)) + (HI(chunk_addr)) + chunk_type; 15 | int i; 16 | for(i = 0; i < length; i++) { 17 | sum += buf[i]; 18 | } 19 | 20 | int complement = (~sum + 1); 21 | return complement & 0xff; 22 | } 23 | 24 | int ihex_read(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end) { 25 | fseek(pFile, 0, SEEK_SET); 26 | unsigned int chunk_len, chunk_addr, chunk_type, i, byte, line_no = 0, greatest_addr = 0; 27 | while(fgets(line, sizeof(line), pFile)) { 28 | line_no++; 29 | // Reading chunk header 30 | if(sscanf(line, ":%02x%04x%02x", &chunk_len, &chunk_addr, &chunk_type) != 3) { 31 | free(buf); 32 | ERROR2("Error while parsing IHEX at line %d\n", line_no); 33 | } 34 | // Reading chunk data 35 | for(i = 9; i < strlen(line) - 1; i +=2) { 36 | if(sscanf(&(line[i]), "%02x", &byte) != 1) { 37 | free(buf); 38 | ERROR2("Error while parsing IHEX at line %d byte %d\n", line_no, i); 39 | } 40 | if(chunk_type != 0x00) { 41 | // The only data records have to be processed 42 | continue; 43 | } 44 | if((i - 9) / 2 >= chunk_len) { 45 | // Respect chunk_len and do not capture checksum as data 46 | break; 47 | } 48 | if(chunk_addr < start) { 49 | free(buf); 50 | ERROR2("Address %04x is out of range at line %d\n", chunk_addr, line_no); 51 | } 52 | if(chunk_addr + chunk_len > end) { 53 | free(buf); 54 | ERROR2("Address %04x + %d is out of range at line %d\n", chunk_addr, chunk_len, line_no); 55 | } 56 | if(chunk_addr + chunk_len > greatest_addr) { 57 | greatest_addr = chunk_addr + chunk_len; 58 | } 59 | buf[chunk_addr - start + (i - 9) / 2] = byte; 60 | } 61 | } 62 | 63 | return(greatest_addr - start); 64 | } 65 | -------------------------------------------------------------------------------- /ihex.h: -------------------------------------------------------------------------------- 1 | #ifndef __IHEX_H 2 | #define __IHEX_H 3 | 4 | int ihex_read(FILE *pFile, unsigned char *buf, unsigned int start, unsigned int end); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* stlink/v2 stm8 memory programming utility 2 | (c) Valentin Dudouyt, 2012 - 2014 */ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "pgm.h" 12 | #ifdef ENABLE_USB 13 | #include "stlink.h" 14 | #include "stlinkv2.h" 15 | #endif 16 | #ifdef ENABLE_SPI 17 | #include "spi.h" 18 | #endif 19 | #include "stm8.h" 20 | #include "ihex.h" 21 | 22 | #ifdef __APPLE__ 23 | extern char *optarg; 24 | extern int optind; 25 | extern int optopt; 26 | extern int opterr; 27 | extern int optreset; 28 | #endif 29 | 30 | programmer_t pgms[] = { 31 | #ifdef ENABLE_USB 32 | { "stlink", 33 | 0x0483, // USB vid 34 | 0x3744, // USB pid 35 | stlink_open, 36 | stlink_close, 37 | stlink_swim_srst, 38 | stlink_swim_read_range, 39 | stlink_swim_write_range, 40 | }, 41 | { 42 | "stlinkv2", 43 | 0x0483, 44 | 0x3748, 45 | stlink2_open, 46 | stlink_close, 47 | stlink2_srst, 48 | stlink2_swim_read_range, 49 | stlink2_swim_write_range, 50 | }, 51 | #endif 52 | #ifdef ENABLE_SPI 53 | { 54 | "spi", 55 | 0, 56 | 0, 57 | spi_open, 58 | spi_close, 59 | spi_swim_srst, 60 | spi_swim_read_range, 61 | spi_swim_write_range, 62 | }, 63 | #endif 64 | { NULL }, 65 | }; 66 | 67 | void print_help_and_exit(const char *name, bool err) { 68 | FILE *stream = err ? stderr : stdout; 69 | fprintf(stream, "Usage: %s [-c programmer] [-p partno] [-s memtype] [-b bytes] [-r|-w|-v] \n", name); 70 | fprintf(stream, "Options:\n"); 71 | fprintf(stream, "\t-? Display this help\n"); 72 | fprintf(stream, "\t-c programmer Specify programmer used (stlink or stlinkv2)\n"); 73 | fprintf(stream, "\t-p partno Specify STM8 device\n"); 74 | fprintf(stream, "\t-l List supported STM8 devices\n"); 75 | fprintf(stream, "\t-s memtype Specify memory type (flash, eeprom, ram, opt or explicit address)\n"); 76 | fprintf(stream, "\t-b bytes Specify number of bytes\n"); 77 | fprintf(stream, "\t-r Read data from device to file\n"); 78 | fprintf(stream, "\t-w Write data from file to device\n"); 79 | fprintf(stream, "\t-v Verify data in device against file\n"); 80 | exit(-err); 81 | } 82 | 83 | void spawn_error(const char *msg) { 84 | fprintf(stderr, "%s\n", msg); 85 | exit(-1); 86 | } 87 | 88 | void dump_pgms(programmer_t *pgms) { 89 | // Dump programmers list in stderr 90 | int i; 91 | for(i = 0; pgms[i].name; i++) 92 | fprintf(stderr, "%s\n", pgms[i].name); 93 | } 94 | 95 | bool is_ext(const char *filename, const char *ext) { 96 | char *ext_begin = strrchr(filename, '.'); 97 | return(ext_begin && strcmp(ext_begin, ext) == 0); 98 | } 99 | 100 | const stm8_device_t *get_part(const char *name) 101 | { 102 | for(unsigned int i = 0; stm8_devices[i].name; i++) 103 | { 104 | const char *e = stm8_devices[i].name; 105 | const char *s = name; 106 | for(e = stm8_devices[i].name, s = name; *s && (*e == *s || *e == '?'); e++, s++); 107 | if(!*e) 108 | return(&stm8_devices[i]); 109 | } 110 | return(0); 111 | } 112 | 113 | int main(int argc, char **argv) { 114 | int start, bytes_count = 0; 115 | char filename[256]; 116 | memset(filename, 0, sizeof(filename)); 117 | // Parsing command line 118 | int c; 119 | action_t action = NONE; 120 | bool start_addr_specified = false, 121 | pgm_specified = false, 122 | part_specified = false, 123 | bytes_count_specified = false; 124 | memtype_t memtype = FLASH; 125 | int i; 126 | programmer_t *pgm = NULL; 127 | const stm8_device_t *part = NULL; 128 | while((c = getopt (argc, argv, "r:w:v:nc:p:s:b:l")) != -1) { 129 | switch(c) { 130 | case 'c': 131 | pgm_specified = true; 132 | for(i = 0; pgms[i].name; i++) { 133 | if(!strcmp(optarg, pgms[i].name)) 134 | pgm = &pgms[i]; 135 | } 136 | break; 137 | case 'p': 138 | part_specified = true; 139 | part = get_part(optarg); 140 | break; 141 | case 'l': 142 | for(i = 0; stm8_devices[i].name; i++) 143 | printf("%s ", stm8_devices[i].name); 144 | printf("\n"); 145 | exit(0); 146 | case 'r': 147 | action = READ; 148 | strcpy(filename, optarg); 149 | break; 150 | case 'w': 151 | action = WRITE; 152 | strcpy(filename, optarg); 153 | break; 154 | case 'v': 155 | action = VERIFY; 156 | strcpy(filename, optarg); 157 | break; 158 | case 's': 159 | // Start addr is depending on MCU type 160 | if(strcasecmp(optarg, "flash") == 0) { 161 | memtype = FLASH; 162 | } else if(strcasecmp(optarg, "eeprom") == 0) { 163 | memtype = EEPROM; 164 | } else if(strcasecmp(optarg, "ram") == 0) { 165 | memtype = RAM; 166 | } else if(strcasecmp(optarg, "opt") == 0) { 167 | memtype = OPT; 168 | } else { 169 | // Start addr is specified explicitely 170 | memtype = UNKNOWN; 171 | int success = sscanf(optarg, "%x", &start); 172 | assert(success); 173 | start_addr_specified = true; 174 | } 175 | break; 176 | case 'b': 177 | bytes_count = atoi(optarg); 178 | bytes_count_specified = true; 179 | break; 180 | case '?': 181 | print_help_and_exit(argv[0], false); 182 | default: 183 | print_help_and_exit(argv[0], true); 184 | } 185 | } 186 | if(argc <= 1) 187 | print_help_and_exit(argv[0], true); 188 | if(pgm_specified && !pgm) { 189 | fprintf(stderr, "No valid programmer specified. Possible values are:\n"); 190 | dump_pgms( (programmer_t *) &pgms); 191 | exit(-1); 192 | } 193 | if(!pgm) 194 | spawn_error("No programmer has been specified"); 195 | if(part_specified && !part) { 196 | fprintf(stderr, "No valid part specified. Use -l to see the list of supported devices.\n"); 197 | exit(-1); 198 | } 199 | if(!part) 200 | spawn_error("No part has been specified"); 201 | 202 | // Try define memory type by address 203 | if(memtype == UNKNOWN) { 204 | if((start >= 0x4800) && (start < 0x4880)) { 205 | memtype = OPT; 206 | } 207 | if((start >= part->ram_start) && (start < part->ram_start + part->ram_size)) { 208 | memtype = RAM; 209 | } 210 | else if((start >= part->flash_start) && (start < part->flash_start + part->flash_size)) { 211 | memtype = FLASH; 212 | } 213 | else if((start >= part->eeprom_start) && (start < part->eeprom_start + part->eeprom_size)) { 214 | memtype = EEPROM; 215 | } 216 | } 217 | 218 | if(memtype != UNKNOWN) { 219 | // Selecting start addr depending on 220 | // specified part and memtype 221 | switch(memtype) { 222 | case RAM: 223 | if(!start_addr_specified) { 224 | start = part->ram_start; 225 | } 226 | if(!bytes_count_specified || bytes_count > part->ram_size) { 227 | bytes_count = part->ram_size; 228 | } 229 | fprintf(stderr, "Determine RAM area\r\n"); 230 | break; 231 | case EEPROM: 232 | if(!start_addr_specified) { 233 | start = part->eeprom_start; 234 | } 235 | if(!bytes_count_specified || bytes_count > part->eeprom_size) { 236 | bytes_count = part->eeprom_size; 237 | } 238 | fprintf(stderr, "Determine EEPROM area\r\n"); 239 | break; 240 | case FLASH: 241 | if(!start_addr_specified) { 242 | start = part->flash_start; 243 | } 244 | if(!bytes_count_specified || bytes_count > part->flash_size) { 245 | bytes_count = part->flash_size; 246 | } 247 | fprintf(stderr, "Determine FLASH area\r\n"); 248 | break; 249 | case OPT: 250 | if(!start_addr_specified) { 251 | start = 0x4800; 252 | } 253 | size_t opt_size = (part->flash_size <= 8*1024 ? 0x40 : 0x80); 254 | if(!bytes_count_specified || bytes_count > opt_size) { 255 | bytes_count = opt_size; 256 | } 257 | fprintf(stderr, "Determine OPT area\r\n"); 258 | break; 259 | } 260 | start_addr_specified = true; 261 | } 262 | if(!action) 263 | spawn_error("No action has been specified"); 264 | if(!start_addr_specified) 265 | spawn_error("No memtype or start_addr has been specified"); 266 | if(!strlen(filename)) 267 | spawn_error("No filename has been specified"); 268 | if(!action || !start_addr_specified || !strlen(filename)) 269 | print_help_and_exit(argv[0], true); 270 | if(!pgm->open(pgm)) 271 | spawn_error("Error communicating with MCU. Please check your SWIM connection."); 272 | FILE *f; 273 | if(action == READ) { 274 | fprintf(stderr, "Reading %d bytes at 0x%x... ", bytes_count, start); 275 | fflush(stderr); 276 | int bytes_count_align = ((bytes_count-1)/256+1)*256; // Reading should be done in blocks of 256 bytes 277 | unsigned char *buf = malloc(bytes_count_align); 278 | if(!buf) spawn_error("malloc failed"); 279 | int recv = pgm->read_range(pgm, part, buf, start, bytes_count_align); 280 | if(recv < bytes_count_align) { 281 | fprintf(stderr, "\r\nRequested %d bytes but received only %d.\r\n", bytes_count_align, recv); 282 | spawn_error("Failed to read MCU"); 283 | } 284 | if(!(f = fopen(filename, "w"))) 285 | spawn_error("Failed to open file"); 286 | fwrite(buf, 1, bytes_count, f); 287 | fclose(f); 288 | fprintf(stderr, "OK\n"); 289 | fprintf(stderr, "Bytes received: %d\n", bytes_count); 290 | } else if (action == VERIFY) { 291 | fprintf(stderr, "Verifing %d bytes at 0x%x... ", bytes_count, start); 292 | fflush(stderr); 293 | 294 | int bytes_count_align = ((bytes_count-1)/256+1)*256; // Reading should be done in blocks of 256 bytes 295 | unsigned char *buf = malloc(bytes_count_align); 296 | if(!buf) spawn_error("malloc failed"); 297 | int recv = pgm->read_range(pgm, part, buf, start, bytes_count_align); 298 | if(recv < bytes_count_align) { 299 | fprintf(stderr, "\r\nRequested %d bytes but received only %d.\r\n", bytes_count_align, recv); 300 | spawn_error("Failed to read MCU"); 301 | } 302 | 303 | if(!(f = fopen(filename, "r"))) 304 | spawn_error("Failed to open file"); 305 | unsigned char *buf2 = malloc(bytes_count); 306 | if(!buf2) spawn_error("malloc failed"); 307 | int bytes_to_verify; 308 | /* reading bytes to RAM */ 309 | if(is_ext(filename, ".ihx")) { 310 | bytes_to_verify = ihex_read(f, buf2, start, start + bytes_count); 311 | } else { 312 | fseek(f, 0L, SEEK_END); 313 | bytes_to_verify = ftell(f); 314 | if(bytes_count_specified) { 315 | bytes_to_verify = bytes_count; 316 | } else if(bytes_count < bytes_to_verify) { 317 | bytes_to_verify = bytes_count; 318 | } 319 | fseek(f, 0, SEEK_SET); 320 | fread(buf2, 1, bytes_to_verify, f); 321 | } 322 | fclose(f); 323 | 324 | if(memcmp(buf, buf2, bytes_to_verify) == 0) { 325 | fprintf(stderr, "OK\n"); 326 | fprintf(stderr, "Bytes verified: %d\n", bytes_to_verify); 327 | } else { 328 | fprintf(stderr, "FAILED\n"); 329 | exit(-1); 330 | } 331 | } else if (action == WRITE) { 332 | if(!(f = fopen(filename, "r"))) 333 | spawn_error("Failed to open file"); 334 | int bytes_count_align = ((bytes_count-1)/part->flash_block_size+1)*part->flash_block_size; 335 | unsigned char *buf = malloc(bytes_count_align); 336 | if(!buf) spawn_error("malloc failed"); 337 | memset(buf, 0, bytes_count_align); // Clean aligned buffer 338 | int bytes_to_write; 339 | 340 | /* reading bytes to RAM */ 341 | if(is_ext(filename, ".ihx")) { 342 | fprintf(stderr, "Writing Intel hex file "); 343 | bytes_to_write = ihex_read(f, buf, start, start + bytes_count); 344 | } else { 345 | fprintf(stderr, "Writing binary file "); 346 | fseek(f, 0L, SEEK_END); 347 | bytes_to_write = ftell(f); 348 | if(bytes_count_specified) { 349 | bytes_to_write = bytes_count; 350 | } else if(bytes_count < bytes_to_write) { 351 | bytes_to_write = bytes_count; 352 | } 353 | fseek(f, 0, SEEK_SET); 354 | fread(buf, 1, bytes_to_write, f); 355 | } 356 | fprintf(stderr, "%d bytes at 0x%x... ", bytes_to_write, start); 357 | 358 | /* flashing MCU */ 359 | int sent = pgm->write_range(pgm, part, buf, start, bytes_to_write, memtype); 360 | if(pgm->reset) { 361 | // Restarting core (if applicable) 362 | pgm->reset(pgm); 363 | } 364 | fprintf(stderr, "OK\n"); 365 | fprintf(stderr, "Bytes written: %d\n", sent); 366 | fclose(f); 367 | } 368 | return(0); 369 | } 370 | -------------------------------------------------------------------------------- /pgm.h: -------------------------------------------------------------------------------- 1 | #ifndef __PGM_H 2 | #define __PGM_H 3 | 4 | #include "stm8.h" 5 | 6 | typedef enum { 7 | UNKNOWN, 8 | RAM, 9 | EEPROM, 10 | FLASH, 11 | OPT, 12 | } memtype_t; 13 | 14 | typedef enum { 15 | NONE = 0, 16 | READ, 17 | WRITE, 18 | VERIFY 19 | } action_t; 20 | 21 | typedef struct programmer_s { 22 | /* Info */ 23 | const char *name; 24 | unsigned int usb_vid; 25 | unsigned int usb_pid; 26 | 27 | /* Methods */ 28 | bool (*open) (struct programmer_s *pgm); 29 | void (*close) (struct programmer_s *pgm); 30 | void (*reset) (struct programmer_s *pgm); 31 | int (*read_range) (struct programmer_s *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length); 32 | int (*write_range) (struct programmer_s *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length, const memtype_t memtype); 33 | 34 | void *ctx; 35 | 36 | /* Private */ 37 | unsigned int msg_count; // debugging only 38 | unsigned int out_msg_size; // stlink/stlinkv2 39 | } programmer_t; 40 | 41 | typedef bool (*pgm_open_cb)(programmer_t *); 42 | typedef void (*pgm_close_cb)(programmer_t *); 43 | typedef int (*pgm_read_range_cb)(programmer_t *, unsigned char *, unsigned int, unsigned int); 44 | typedef int (*pgm_write_range_cb)(programmer_t *, unsigned char *, unsigned int, unsigned int); 45 | 46 | #endif 47 | 48 | -------------------------------------------------------------------------------- /spi.c: -------------------------------------------------------------------------------- 1 | /* spi-based SWIM implementation 2 | (c) Andrzej Szombierski 2016 */ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "spi.h" 15 | #include "pgm.h" 16 | #include "utils.h" 17 | 18 | //#define DEBUG_SPI 19 | 20 | #define SPI_DEVICE "/dev/spidev0.0" 21 | #define RST_GPIO "25" 22 | #define RISETIME_WORKAROUND 2 23 | 24 | // equal to HSI clock 25 | #define SPI_FREQMHZ 8 26 | 27 | #define SPI_BITS1US SPI_FREQMHZ 28 | #define SPI_BYTES1MS (1000*SPI_BITS1US/8) 29 | 30 | #define SWIM_SRST 0 31 | #define SWIM_ROTF 1 32 | #define SWIM_WOTF 2 33 | 34 | struct bitbuf { 35 | unsigned char *cur, *end; 36 | int bit; 37 | }; 38 | 39 | static void bb_extend(struct bitbuf *bb) 40 | { 41 | bb->cur++; 42 | bb->bit=0; 43 | assert(bb->cur < bb->end); 44 | } 45 | 46 | static inline void bb_put(struct bitbuf *bb, int bit) 47 | { 48 | *bb->cur = (*bb->cur<<1) | (!!bit); 49 | bb->bit++; 50 | if(bb->bit == 8) 51 | bb_extend(bb); 52 | } 53 | 54 | static inline int bb_get(struct bitbuf *bb) 55 | { 56 | if(bb->cur == bb->end) 57 | return -1; 58 | 59 | int rv = !!(*bb->cur & 0x80); 60 | *bb->cur <<= 1; 61 | bb->bit++; 62 | if(bb->bit == 8) { 63 | bb->cur++; 64 | bb->bit=0; 65 | } 66 | return rv; 67 | } 68 | 69 | static void bb_flush(struct bitbuf *bb, int bit) { 70 | while(bb->bit) 71 | bb_put(bb, bit); 72 | } 73 | 74 | static void bb_init(struct bitbuf * bb, unsigned char *buf, int len) 75 | { 76 | bb->cur = buf; 77 | bb->end = buf+len; 78 | bb->bit=0; 79 | } 80 | 81 | // low-speed SWIM bit 82 | // ajusted for slow-ish rise time 83 | static inline void ls_bit(struct bitbuf *bb, int bit) 84 | { 85 | int i; 86 | for(i=0;i<(bit ? 2 : (20-RISETIME_WORKAROUND));i++) 87 | bb_put(bb, 1); 88 | for(i=0;i<(bit ? 20 : (2+RISETIME_WORKAROUND));i++) 89 | bb_put(bb, 0); 90 | } 91 | 92 | // space for low-speed SWIM bit 93 | static inline void ls_space(struct bitbuf *bb, int n) 94 | { 95 | int i; 96 | for(i=0;i<22*n;i++) 97 | bb_put(bb, 0); 98 | } 99 | 100 | static int decode_ls_bits(struct bitbuf *bb, int nbits, int *out) 101 | { 102 | int i,j; 103 | int old=1,n=0; 104 | int count=0; 105 | *out = 0; 106 | while(nbits>0) { 107 | int b=bb_get(bb); 108 | if(b < 0) 109 | return count; 110 | 111 | if(b!=old) { 112 | old=b; 113 | if(b) { 114 | *out=(*out<<1) | ((n<9)?1:0); 115 | count++; 116 | nbits--; 117 | } 118 | n=0; 119 | } 120 | n++; 121 | } 122 | return count; 123 | } 124 | 125 | 126 | 127 | static void swim_cmd(struct bitbuf *bb, int cmd) 128 | { 129 | int p = ((cmd>>2)^(cmd>>1)^cmd)&1; 130 | ls_bit(bb, 0); // host 131 | ls_bit(bb, cmd&4); // b2 132 | ls_bit(bb, cmd&2); // b1 133 | ls_bit(bb, cmd&1); // b0 134 | ls_bit(bb, p); // bp 135 | ls_space(bb, 1); // ack 136 | } 137 | 138 | static void swim_byte(struct bitbuf *bb, int byte) 139 | { 140 | int p = ((byte>>7)^(byte>>6)^(byte>>5)^(byte>>4)^(byte>>3)^(byte>>2)^(byte>>1)^byte)&1; 141 | ls_bit(bb, 0); // host 142 | ls_bit(bb, byte&128); // b7 143 | ls_bit(bb, byte&64); // b6 144 | ls_bit(bb, byte&32); // b5 145 | ls_bit(bb, byte&16); // b4 146 | ls_bit(bb, byte&8); // b3 147 | ls_bit(bb, byte&4); // b2 148 | ls_bit(bb, byte&2); // b1 149 | ls_bit(bb, byte&1); // b0 150 | ls_bit(bb, p); // bp 151 | ls_space(bb, 1); // ack 152 | } 153 | 154 | static void swim_rotf(struct bitbuf *bb, int address, int len) 155 | { 156 | swim_cmd(bb, SWIM_ROTF); 157 | swim_byte(bb, len); 158 | swim_byte(bb, address>>16); 159 | swim_byte(bb, address>>8); 160 | swim_byte(bb, address); 161 | // send ack later 162 | } 163 | 164 | static void swim_wotf(struct bitbuf *bb, int address, int len, const unsigned char *data) 165 | { 166 | swim_cmd(bb, SWIM_WOTF); 167 | swim_byte(bb, len); 168 | swim_byte(bb, address>>16); 169 | swim_byte(bb, address>>8); 170 | swim_byte(bb, address); 171 | for(;len>0;--len) 172 | swim_byte(bb, *data++); 173 | } 174 | 175 | static bool swim_ack_check(struct bitbuf *bb, int n_bytes) 176 | { 177 | int rv, dec, i; 178 | dec = decode_ls_bits(bb, 6, &rv); 179 | if(dec != 6 || (rv&1) != 1) { // find ACK 180 | return false; 181 | } 182 | 183 | for(i=0;i24) 208 | putchar('-'); 209 | n=0; 210 | } 211 | n++; 212 | q<<=1; 213 | } 214 | if((i&7)==0) 215 | putchar('.'); 216 | } 217 | printf("\n"); 218 | } 219 | 220 | void dump(unsigned char *ptr, int len, int x) 221 | { 222 | int i,j; 223 | for(i=0;icur-buf; 242 | } 243 | assert(rcvlen >= bb->cur - buf); 244 | assert(bb->end - buf >= rcvlen); 245 | memset(bb->cur, 0, rcvlen-(bb->cur-buf)); 246 | struct spi_ioc_transfer tf = { 247 | (__u64)(intptr_t)buf, (__u64)(intptr_t)rcvbuf, 248 | rcvlen, 249 | }; 250 | 251 | if(ioctl(spi, SPI_IOC_MESSAGE(1), &tf) != rcvlen) { 252 | fprintf(stderr, "Kernel rejected SPI transaction: %m\n"); 253 | return false; 254 | } 255 | #ifdef DEBUG_SPI 256 | printf("\n"); 257 | //dump(buf, rcvlen, 0xff); 258 | //dump(rcvbuf, rcvlen, 0); 259 | printf("CMD >"); 260 | decode(buf, bb->cur-buf, 0xff); 261 | printf("RSP >"); 262 | decode(rcvbuf, rcvlen, 0); 263 | printf("\n"); 264 | #endif 265 | return true; 266 | } 267 | 268 | bool send_sync_sequence(int spi, int *sync); 269 | int spi_swim_read_byte(programmer_t *pgm, unsigned int start) 270 | { 271 | unsigned char sndbuf[256], rcvbuf[256]; 272 | struct bitbuf bb; 273 | int retry = 3; 274 | while(retry > 0) { 275 | //printf("Read byte %x\n", start); 276 | bb_init(&bb, sndbuf, sizeof(sndbuf)); 277 | swim_rotf(&bb, start, 1); 278 | if(!spi_transact(((spi_context_t*)pgm->ctx)->spi_fd, sndbuf, &bb, rcvbuf, sizeof(rcvbuf))) 279 | return -1; 280 | 281 | bb_init(&bb, rcvbuf, sizeof(rcvbuf)); 282 | if(swim_ack_check(&bb, 4)) { 283 | int rv, dec; 284 | dec = decode_ls_bits(&bb, 100, &rv); 285 | int byte=0; 286 | 287 | if(dec == 10 && rv & 512) { 288 | byte = (rv>>1)&255; 289 | int p = ((byte>>7)^(byte>>6)^(byte>>5)^(byte>>4)^(byte>>3)^(byte>>2)^(byte>>1)^byte) & 1; 290 | if((rv&1)==p) { 291 | // ok 292 | bb_init(&bb, sndbuf, sizeof(sndbuf)); 293 | ls_bit(&bb, 1); // send ack 294 | if(!spi_transact(((spi_context_t*)pgm->ctx)->spi_fd, sndbuf, &bb, rcvbuf, sizeof(rcvbuf))) 295 | return -1; 296 | 297 | return byte; 298 | 299 | } else { 300 | //fprintf(stderr, "byte = %x PARITY ERROR %x\n", byte, rv); 301 | } 302 | } else { 303 | //fprintf(stderr, "read byte: decode error %d %x\n", dec, rv); 304 | } 305 | } 306 | 307 | fprintf(stderr, "(retrying read command)"); 308 | --retry; 309 | if(!send_sync_sequence(((spi_context_t*)pgm->ctx)->spi_fd, NULL)) // the whole sync sequence is not required, but this makes things simpler 310 | return -1; 311 | } 312 | 313 | fprintf(stderr, "Fatal SWIM Communications error\n"); 314 | return -1; 315 | } 316 | 317 | bool spi_swim_write_byte(programmer_t *pgm, unsigned char byte, unsigned int start) 318 | { 319 | unsigned char sndbuf[256], rcvbuf[256]; 320 | struct bitbuf bb; 321 | int retry=3; 322 | while(retry > 0) { 323 | bb_init(&bb, sndbuf, sizeof(sndbuf)); 324 | swim_wotf(&bb, start, 1, &byte); 325 | if(!spi_transact(((spi_context_t*)pgm->ctx)->spi_fd, sndbuf, &bb, rcvbuf, sizeof(rcvbuf))) 326 | return false; 327 | 328 | bb_init(&bb, rcvbuf, sizeof(rcvbuf)); 329 | if(swim_ack_check(&bb, 4+1)) 330 | return true; 331 | 332 | fprintf(stderr, "(retrying write command)"); 333 | --retry; 334 | if(!send_sync_sequence(((spi_context_t*)pgm->ctx)->spi_fd, NULL)) // the whole sync sequence is not required, but this makes things simpler 335 | return false; 336 | } 337 | 338 | fprintf(stderr, "Fatal SWIM Communications error\n"); 339 | return false; 340 | } 341 | 342 | bool spi_init_session(programmer_t *pgm) { 343 | return spi_swim_write_byte(pgm, 0xa0, 0x7f80); // mov 0x0a, SWIM_CSR2 ;; Init SWIM 344 | //spi_swim_write_byte(pgm, 0xb0, 0x7f80); 345 | //spi_swim_write_byte(pgm, 0xb4, 0x7f80); 346 | } 347 | 348 | bool spi_finish_session(programmer_t *pgm) { 349 | return spi_swim_write_byte(pgm, 0xb6, 0x7f80); 350 | } 351 | 352 | bool send_sync_sequence(int spi, int *sync_value) { 353 | unsigned char sndbuf[32*SPI_BITS1US/8 + SPI_BYTES1MS * 7]; 354 | unsigned char rcvbuf[sizeof(sndbuf)]; 355 | int q=0; 356 | int i,j; 357 | int sync_start; 358 | struct bitbuf bb; 359 | for(i=0;i<16*SPI_BITS1US/8;i++) 360 | sndbuf[q++] = 0; // low init 361 | 362 | for(i=0;i<16*SPI_BITS1US/8;i++) // 16us 363 | sndbuf[q++] = 0xff; // high 16us 364 | 365 | for(i=0;i<4;i++) { 366 | for(j=0;j= 0) { 444 | write(fd, RST_GPIO, strlen(RST_GPIO)); 445 | close(fd); 446 | } 447 | 448 | fd = open("/sys/class/gpio/gpio" RST_GPIO "/direction", O_RDWR); 449 | } 450 | 451 | if(fd < 0) { 452 | fprintf(stderr, "Can't open gpio" RST_GPIO "/direction: %m\n"); 453 | close(spi); 454 | return false; 455 | } 456 | 457 | // RESET 458 | if(write(fd, "low", 3) != 3) { 459 | fprintf(stderr, "Can't write to gpio" RST_GPIO "/direction: %m\n"); 460 | close(spi); 461 | close(fd); 462 | return false; 463 | } 464 | 465 | // workaround for buggy RPI3 SPI driver stack 466 | int clock_rates[] = { 467 | 1000000 * SPI_FREQMHZ, 468 | 1000000 * 500 / 250 * SPI_FREQMHZ, 469 | 1000000 * 500 / 350 * SPI_FREQMHZ, 470 | 1000000 * 500 / 400 * SPI_FREQMHZ, 471 | 0, 472 | }; 473 | 474 | int clock; 475 | for(clock=0;;clock++) { 476 | if(!clock_rates[clock]) { 477 | fprintf(stderr, "Could not communicate with target\n"); 478 | return false; 479 | } 480 | 481 | if(ioctl(spi, SPI_IOC_WR_MAX_SPEED_HZ, &clock_rates[clock])) { 482 | fprintf(stderr, "Can't set SPI frequency: %m\n"); 483 | return false; 484 | } 485 | 486 | // sync sequence 487 | int sync; 488 | if(!send_sync_sequence(spi, &sync)) 489 | continue; 490 | //printf("sync = %d\n", sync); 491 | 492 | if(sync > 100 && sync < 140) { // valid sync pulse length 493 | if(clock != 0) { 494 | fprintf(stderr, "WARNING: SPI driver problem, configured as %dMHz runs at %dMHz\n" 495 | "For Raspberry Pi specific solutions, see https://github.com/raspberrypi/linux/issues/2094\n", 496 | clock_rates[clock]/1000000, clock_rates[0]/1000000); 497 | } 498 | break; 499 | } 500 | } 501 | 502 | spi_context_t *ctx = malloc(sizeof(spi_context_t)); 503 | ctx->spi_fd = spi; 504 | pgm->ctx = ctx; 505 | 506 | if(!spi_swim_write_byte(pgm, 0xa0, 0x7f80)) // mov 0x0a, SWIM_CSR2 ;; Init SWIM 507 | return false; 508 | 509 | // de-reset 510 | fd = open("/sys/class/gpio/gpio" RST_GPIO "/direction", O_RDWR); 511 | if(fd >= 0) { 512 | write(fd, "in", 2); 513 | close(fd); 514 | } 515 | usleep(1000); 516 | 517 | return(true); 518 | } 519 | 520 | void spi_close(programmer_t *pgm) { 521 | // de-reset 522 | int fd = open("/sys/class/gpio/gpio" RST_GPIO "/direction", O_RDWR); 523 | if(fd >= 0) { 524 | write(fd, "in", 2); 525 | close(fd); 526 | } 527 | 528 | spi_context_t *ctx = pgm->ctx; 529 | close(ctx->spi_fd); 530 | free(pgm->ctx); 531 | } 532 | 533 | void spi_srst(programmer_t *pgm) { 534 | // RESET 535 | int fd = open("/sys/class/gpio/gpio" RST_GPIO "/direction", O_RDWR); 536 | if(fd >= 0) { 537 | write(fd, "low", 3); 538 | close(fd); 539 | } 540 | 541 | usleep(10000); 542 | 543 | // de-reset 544 | fd = open("/sys/class/gpio/gpio" RST_GPIO "/direction", O_RDWR); 545 | if(fd >= 0) { 546 | write(fd, "in", 2); 547 | close(fd); 548 | } 549 | } 550 | 551 | void spi_swim_srst(programmer_t *pgm) { 552 | unsigned char sndbuf[256], rcvbuf[256]; 553 | struct bitbuf bb; 554 | bb_init(&bb, sndbuf, sizeof(sndbuf)); 555 | swim_cmd(&bb, SWIM_SRST); 556 | spi_transact(((spi_context_t*)pgm->ctx)->spi_fd, sndbuf, &bb, rcvbuf, sizeof(rcvbuf)); 557 | } 558 | 559 | int spi_swim_read_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length) { 560 | unsigned char buf[4]; 561 | DEBUG_PRINT("spi_swim_read_range\n"); 562 | spi_init_session(pgm); 563 | spi_swim_write_byte(pgm, 0x00, device->regs.CLK_CKDIVR); // mov 0x00, CLK_DIVR 564 | memset(buffer, 0xff, length); 565 | 566 | int nr=0, retry=3; 567 | while(length > 0) { 568 | unsigned char sndbuf[4096], rcvbuf[4096]; 569 | struct bitbuf bb; 570 | bb_init(&bb, sndbuf, sizeof(sndbuf)); 571 | int l = length; 572 | if(l > 64) l = 64; 573 | swim_rotf(&bb, start, l); 574 | ls_space(&bb, 1); // remote ack 575 | 576 | int i; 577 | for(i=0;ictx)->spi_fd, sndbuf, &bb, rcvbuf, sizeof(rcvbuf))) 583 | break; 584 | 585 | bb_init(&bb, rcvbuf, sizeof(rcvbuf)); 586 | 587 | bool ok = true; 588 | if(swim_ack_check(&bb, 4)) { 589 | for(i=0;i>1)&255; 594 | int p = ((byte>>7)^(byte>>6)^(byte>>5)^(byte>>4)^(byte>>3)^(byte>>2)^(byte>>1)^byte) & 1; 595 | if((rv&1)==p) { 596 | *buffer++ = byte; 597 | nr++; 598 | } else { 599 | // fprintf(stderr, "byte %d = %x PARITY ERROR %x\n", i, byte, rv); 600 | ok = false; 601 | break; 602 | } 603 | } else { 604 | //fprintf(stderr, "read range: decode error %d %x\n", dec, rv); 605 | ok = false; 606 | break; 607 | } 608 | 609 | // my ack 610 | dec = decode_ls_bits(&bb, 1, &rv); 611 | if(dec != 1 || rv != 1) { 612 | ok = false; 613 | break; 614 | } 615 | } 616 | } else { 617 | ok = false; 618 | } 619 | 620 | if(ok) { 621 | start += l; 622 | length -= l; 623 | retry = 3; 624 | 625 | } else { 626 | if(retry == 0) { 627 | fprintf(stderr, "Fatal SWIM Communications error\n"); 628 | break; 629 | } 630 | 631 | fprintf(stderr, "(retrying read command)"); 632 | --retry; 633 | if(!send_sync_sequence(((spi_context_t*)pgm->ctx)->spi_fd, NULL)) // the whole sync sequence is not required, but this makes things simpler 634 | break; 635 | } 636 | } 637 | 638 | spi_finish_session(pgm); 639 | return(nr); 640 | } 641 | 642 | int spi_swim_write_block(programmer_t *pgm, unsigned char *buffer, 643 | unsigned int start, 644 | unsigned int length 645 | ) 646 | { 647 | unsigned char sndbuf[4096]; 648 | struct bitbuf bb; 649 | bb_init(&bb, sndbuf, sizeof(sndbuf)); 650 | swim_wotf(&bb, start, length, buffer); 651 | ls_space(&bb, 2); // for remote ack 652 | if(!spi_transact(((spi_context_t*)pgm->ctx)->spi_fd, sndbuf, &bb, 0, 0)) 653 | return -1; 654 | 655 | return(0); 656 | } 657 | 658 | int spi_swim_write_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length, const memtype_t memtype) { 659 | int i; 660 | spi_init_session(pgm); 661 | // spi_swim_write_byte(pgm, 0x00, device->regs.CLK_CKDIVR); 662 | if(memtype == FLASH || memtype == EEPROM || memtype == OPT) { 663 | spi_swim_write_byte(pgm, 0x00, device->regs.FLASH_IAPSR); 664 | } 665 | if(memtype == FLASH) { 666 | spi_swim_write_byte(pgm, 0x56, device->regs.FLASH_PUKR); 667 | spi_swim_write_byte(pgm, 0xae, device->regs.FLASH_PUKR); 668 | } 669 | if(memtype == EEPROM || memtype == OPT) { 670 | spi_swim_write_byte(pgm, 0xae, device->regs.FLASH_DUKR); 671 | spi_swim_write_byte(pgm, 0x56, device->regs.FLASH_DUKR); 672 | } 673 | if(memtype == FLASH || memtype == EEPROM || memtype == OPT) { 674 | spi_swim_write_byte(pgm, 0x56, device->regs.FLASH_IAPSR); 675 | } 676 | int flash_block_size = device->flash_block_size; 677 | for(i = 0; i < length; i+=flash_block_size) { 678 | unsigned char block[128]; 679 | memset(block, 0, sizeof(block)); 680 | int block_size = length - i; 681 | if(block_size > flash_block_size) 682 | block_size = flash_block_size; 683 | DEBUG_PRINT("Writing block %04x with size %d\n", start+i, block_size); 684 | memcpy(block, buffer+i, block_size); 685 | if(block_size < flash_block_size) { 686 | DEBUG_PRINT("Padding block %04x with %d zeroes\n", 687 | start+i, 688 | flash_block_size - block_size); 689 | block_size = flash_block_size; 690 | } 691 | if(memtype == FLASH || memtype == EEPROM || memtype == OPT) { 692 | spi_swim_write_byte(pgm, 0x01, device->regs.FLASH_CR2); 693 | if(device->regs.FLASH_NCR2 != 0) { // Device have FLASH_NCR2 register 694 | spi_swim_write_byte(pgm, 0xFE, device->regs.FLASH_NCR2); 695 | } 696 | } 697 | int result = spi_swim_write_block(pgm, block, start + i, block_size); 698 | if(result) 699 | fprintf(stderr, "Write error\n"); 700 | 701 | bool fail=false; 702 | for(;;) { 703 | int iapsr = spi_swim_read_byte(pgm, device->regs.FLASH_IAPSR); 704 | if(iapsr < 0) { 705 | fprintf(stderr, "Transfer error\n"); 706 | fail=true; 707 | break; 708 | } 709 | if(iapsr & 1) { 710 | fprintf(stderr, "Write error %x (protected?)\n", iapsr); 711 | fail=true; 712 | break; 713 | } 714 | 715 | if(iapsr & 4) { 716 | break; 717 | } 718 | } 719 | 720 | if(fail) break; 721 | 722 | } 723 | if(memtype == FLASH || memtype == EEPROM || memtype == OPT) { 724 | spi_swim_write_byte(pgm, 0x56, device->regs.FLASH_IAPSR); 725 | } 726 | spi_finish_session(pgm); 727 | return(i); 728 | } 729 | -------------------------------------------------------------------------------- /spi.h: -------------------------------------------------------------------------------- 1 | /* spi device driver 2 | (c) Andrzej Szombierski, 2016 */ 3 | 4 | #ifndef __SPI_H 5 | #define __SPI_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include "pgm.h" 11 | 12 | typedef struct spi_context_s { 13 | int spi_fd; 14 | } spi_context_t; 15 | 16 | typedef enum { 17 | SPI_OK = 0, 18 | SPI_SPI_ERROR, 19 | SPI_SWIM_ERROR 20 | } spi_status_t; 21 | 22 | bool spi_open(programmer_t *pgm); 23 | void spi_close(programmer_t *pgm); 24 | void spi_srst(programmer_t *pgm); 25 | void spi_swim_srst(programmer_t *pgm); 26 | int spi_swim_read_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length); 27 | int spi_swim_write_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length, const memtype_t memtype); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /stlink.c: -------------------------------------------------------------------------------- 1 | /* stlink common and stlink-v1 specific functions 2 | (c) Valentin Dudouyt, 2012-2013 */ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "stm8.h" 15 | #include "pgm.h" 16 | #include "stlink.h" 17 | #include "utils.h" 18 | #include "usb.h" 19 | 20 | #define STLK_FLAG_ERR 0x01 21 | #define STLK_FLAG_BUFFER_FULL 0x04 22 | #define STLK_READ_BUFFER_SIZE 6144 23 | #define STLK_MAX_WRITE 512 24 | 25 | unsigned int stlink_swim_get_status(programmer_t *pgm); 26 | int stlink_swim_read_byte(programmer_t *pgm, unsigned char byte, unsigned int start); 27 | int stlink_swim_write_byte(programmer_t *pgm, unsigned char byte, unsigned int start); 28 | 29 | void stlink_send_message(programmer_t *pgm, int count, ...) { 30 | va_list ap; 31 | unsigned char data[32]; 32 | int i, r, actual; 33 | 34 | va_start(ap, count); 35 | assert(pgm->out_msg_size < sizeof(data)); 36 | assert(count <= pgm->out_msg_size); 37 | memset(data, 0, pgm->out_msg_size); 38 | for(i = 0; i < count; i++) 39 | data[i] = va_arg(ap, int); 40 | r = libusb_bulk_transfer(DEV_HANDLE(pgm), (2 | LIBUSB_ENDPOINT_OUT), data, pgm->out_msg_size, &actual, 0); 41 | assert(r == 0); 42 | pgm->msg_count++; 43 | return; 44 | } 45 | 46 | int stlink_read(programmer_t *pgm, unsigned char *buffer, int count) { 47 | int r, recv; 48 | r = libusb_bulk_transfer(DEV_HANDLE(pgm), (1 | LIBUSB_ENDPOINT_IN), buffer, count, &recv, 0); 49 | assert(r==0); 50 | return(recv); 51 | } 52 | 53 | int stlink_read1(programmer_t *pgm, int count) { 54 | unsigned char buf[16]; 55 | return(stlink_read(pgm, buf, count)); 56 | } 57 | 58 | int stlink_read_and_cmp(programmer_t *pgm, int count, ...) { 59 | va_list ap; 60 | unsigned char buf[16]; 61 | int recv = stlink_read(pgm, buf, count); 62 | int i, ret = 0; 63 | va_start(ap, count); 64 | for(i = 0; i < count; i++) { 65 | if(buf[i] != va_arg(ap, int)) 66 | ret++; 67 | } 68 | return(ret); 69 | } 70 | 71 | unsigned char *pack_int16(uint16_t word, unsigned char *out) { 72 | // Filling with bytes in big-endian order 73 | out[0] = (word & 0xff00) >> 8; 74 | out[1] = (word & 0x00ff); 75 | return(out+2); 76 | } 77 | 78 | uint16_t unpack_int16_le(unsigned char *block) { 79 | uint32_t ret; 80 | ret = *(block + 1) << 8; 81 | ret += *(block + 0); 82 | return(ret); 83 | } 84 | 85 | uint16_t unpack_int16(unsigned char *block) { 86 | uint32_t ret; 87 | ret = *(block + 0) << 8; 88 | ret += *(block + 1); 89 | return(ret); 90 | } 91 | 92 | unsigned char *pack_int32(uint32_t word, unsigned char *out) { 93 | out[0] = (word & 0xff000000) >> 24; 94 | out[1] = (word & 0x00ff0000) >> 16; 95 | out[2] = (word & 0x0000ff00) >> 8; 96 | out[3] = (word & 0x000000ff); 97 | return(out+4); 98 | } 99 | 100 | unsigned char *pack_int32_le(uint32_t word, unsigned char *out) { 101 | // Filling with bytes in little-endian order 102 | out[0] = (word & 0x000000ff); 103 | out[1] = (word & 0x0000ff00) >> 8; 104 | out[2] = (word & 0x00ff0000) >> 16; 105 | out[3] = (word & 0xff000000) >> 24; 106 | return(out+4); 107 | } 108 | 109 | uint32_t unpack_int32(unsigned char *block) { 110 | uint32_t ret; 111 | ret = *(block + 0) << 24; 112 | ret += *(block + 1) << 16; 113 | ret += *(block + 2) << 8; 114 | ret += *(block + 3); 115 | return(ret); 116 | } 117 | 118 | uint32_t unpack_int32_le(unsigned char *block) { 119 | uint32_t ret; 120 | ret = *(block + 3) << 24; 121 | ret += *(block + 2) << 16; 122 | ret += *(block + 1) << 8; 123 | ret += *(block + 0); 124 | return(ret); 125 | } 126 | 127 | void pack_usb_cbw(scsi_usb_cbw *cbw, unsigned char *out) { 128 | unsigned char *offset = out; 129 | offset = pack_int32(cbw->signature, offset); 130 | offset = pack_int32(cbw->tag, offset); 131 | offset = pack_int32_le(cbw->transfer_length, offset); 132 | offset[0] = cbw->flags; 133 | offset[1] = cbw->LUN; 134 | offset[2] = cbw->cblength; 135 | offset += 3; 136 | memcpy(offset, cbw->cb, sizeof(cbw->cb)); 137 | offset += sizeof(cbw->cb); 138 | assert(offset - out == USB_CBW_SIZE); 139 | } 140 | 141 | void unpack_usb_csw(unsigned char *block, scsi_usb_csw *out) { 142 | out->signature = unpack_int32(block); 143 | out->tag = unpack_int32(block + 4); 144 | out->data_residue = unpack_int32_le(block + 8); 145 | out->status = block[12]; 146 | } 147 | 148 | int stlink_send_cbw(libusb_device_handle *dev_handle, scsi_usb_cbw *cbw) { 149 | unsigned char buf[USB_CBW_SIZE]; 150 | cbw->signature = USB_CBW_SIGNATURE; 151 | cbw->tag = 0x707ec281; 152 | pack_usb_cbw(cbw, buf); 153 | int actual; 154 | int r = libusb_bulk_transfer(dev_handle, 155 | (2 | LIBUSB_ENDPOINT_OUT), 156 | buf, 157 | USB_CBW_SIZE, 158 | &actual, 159 | 0); 160 | assert(actual == USB_CBW_SIZE); 161 | return(r); 162 | } 163 | 164 | int stlink_read_csw(libusb_device_handle *dev_handle, scsi_usb_csw *csw) { 165 | unsigned char buf[USB_CSW_SIZE]; 166 | int recv; 167 | int r = libusb_bulk_transfer(dev_handle, 168 | (1 | LIBUSB_ENDPOINT_IN), 169 | buf, 170 | USB_CSW_SIZE, 171 | &recv, 172 | 0); 173 | assert(recv == USB_CSW_SIZE); 174 | unpack_usb_csw(buf, csw); 175 | return(r); 176 | } 177 | 178 | scsi_usb_cbw cbw; 179 | scsi_usb_csw csw; 180 | 181 | int stlink_test_unit_ready(programmer_t *pgm) { 182 | // This is a default SCSI command 183 | memset(&cbw, 0, sizeof(scsi_usb_cbw)); 184 | cbw.cblength = 0x06; 185 | int r; 186 | r = stlink_send_cbw(DEV_HANDLE(pgm), &cbw); 187 | assert(r == 0); 188 | r = stlink_read_csw(DEV_HANDLE(pgm), &csw); 189 | assert(r == 0); 190 | return(csw.status == 0); 191 | } 192 | 193 | int stlink_cmd(programmer_t *pgm, int transfer_length, unsigned char *transfer_out, unsigned char flags, 194 | int cblength, ...) { 195 | va_list ap; 196 | memset(&cbw, 0, sizeof(scsi_usb_cbw)); 197 | cbw.transfer_length = transfer_length; 198 | cbw.flags = flags; 199 | cbw.cblength = cblength; 200 | va_start(ap, cblength); 201 | int i; 202 | for(i = 0; i < cblength; i++) { 203 | cbw.cb[i] = va_arg(ap, int); 204 | } 205 | assert( stlink_send_cbw(DEV_HANDLE(pgm), &cbw) == 0); 206 | if(transfer_length) { 207 | // Transfer expected, read some raw data 208 | if(transfer_out) 209 | stlink_read(pgm, transfer_out, transfer_length); 210 | else 211 | stlink_read1(pgm, transfer_length); 212 | } 213 | // Reading status 214 | stlink_read_csw(DEV_HANDLE(pgm), &csw); 215 | return(csw.status == 0); 216 | } 217 | 218 | int stlink_cmd_swim_read(programmer_t *pgm, uint16_t length, uint16_t start) { 219 | memset(&cbw, 0, sizeof(scsi_usb_cbw)); 220 | cbw.transfer_length = length; 221 | cbw.flags = 0x80; 222 | cbw.cblength = 0x0a; 223 | cbw.cb[0] = 0xf4; 224 | cbw.cb[1] = 0x0c; 225 | pack_int16(length, cbw.cb+2); 226 | pack_int16(start, cbw.cb+6); 227 | return 0; 228 | } 229 | 230 | void stlink_init_session(programmer_t *pgm) { 231 | int i; 232 | char f4_cmd_arg1[] = { 0x07, 233 | 0x07, 234 | 0x08, 235 | 0x07, 236 | 0x04, 237 | }; 238 | for(i = 0; i < sizeof(f4_cmd_arg1); i++) { 239 | stlink_cmd(pgm, 0, NULL, 0x00, 0x0a, 240 | 0xf4, f4_cmd_arg1[i], 241 | 0x01, 0x00, 242 | 0x00, 0x00, 243 | 0x00, 0x00, 244 | 0x00, 0x00); 245 | stlink_swim_get_status(pgm); 246 | } 247 | do { 248 | usleep(10000); 249 | } while ((stlink_swim_get_status(pgm) & 1) != 0); 250 | stlink_cmd(pgm, 0, NULL, 0x00, 0x03, 251 | 0xf4, 0x03, 252 | 0x00, 0x00, 253 | 0x00, 0x00, 254 | 0x00, 0x00, 255 | 0x00, 0x00); 256 | stlink_swim_get_status(pgm); 257 | stlink_cmd(pgm, 0, NULL, 0x00, 0x0a, 258 | 0xf4, 0x05, 259 | 0x00, 0x00, 260 | 0x00, 0x00, 261 | 0x00, 0x00, 262 | 0x00, 0x00); 263 | stlink_swim_get_status(pgm); 264 | 265 | stlink_swim_write_byte(pgm, 0xa0, 0x7f80); // mov 0x0a, SWIM_CSR2 ;; Init SWIM 266 | stlink_cmd(pgm, 0, NULL, 0x00, 0x0a, 267 | 0xf4, 0x08, 268 | 0x00, 0x01, 269 | 0x00, 0x00, 270 | 0x7f, 0x80, 271 | 0xa0, 0x00); 272 | stlink_swim_get_status(pgm); 273 | stlink_cmd(pgm, 0, NULL, 0x00, 0x0a, 274 | 0xf4, 0x06, 275 | 0x00, 0x01, 276 | 0x00, 0x00, 277 | 0x7f, 0x99, 278 | 0xa0, 0x00); 279 | stlink_swim_get_status(pgm); 280 | stlink_swim_write_byte(pgm, 0xb0, 0x7f80); 281 | stlink_cmd(pgm, 0, NULL, 0x00, 0x03, // Elsewise, only zeroes will be received 282 | 0xf4, 0x03, 283 | 0x01); 284 | stlink_swim_get_status(pgm); 285 | stlink_swim_write_byte(pgm, 0xb4, 0x7f80); 286 | } 287 | 288 | void stlink_finish_session(programmer_t *pgm) { 289 | stlink_swim_write_byte(pgm, 0xb6, 0x7f80); 290 | stlink_cmd(pgm, 0, NULL, 0x00, 0x0a, 291 | 0xf4, 0x05, 292 | 0x00, 0x01, 293 | 0x00, 0x00, 294 | 0x7f, 0x80, 295 | 0xb6, 0x00); 296 | stlink_swim_get_status(pgm); 297 | stlink_cmd(pgm, 0, NULL, 0x00, 0x0a, 298 | 0xf4, 0x07, 299 | 0x00, 0x01, 300 | 0x00, 0x00, 301 | 0x7f, 0x80, 302 | 0xb6, 0x00); 303 | stlink_swim_get_status(pgm); 304 | stlink_cmd(pgm, 0, NULL, 0x00, 0x03, 305 | 0xf4, 0x03, 306 | 0x01); 307 | stlink_swim_get_status(pgm); 308 | } 309 | 310 | unsigned int stlink_swim_get_status(programmer_t *pgm) { 311 | unsigned char buf[4]; 312 | stlink_cmd(pgm, 4, buf, 0x80, 0x0a, 313 | 0xf4, 0x09, 314 | 0x01, 0x00, 315 | 0x00, 0x00, 316 | 0x00, 0x00, 317 | 0x00, 0x00); 318 | return(unpack_int32_le(buf)); 319 | } 320 | 321 | bool stlink_open(programmer_t *pgm) { 322 | unsigned char buf[18]; 323 | if(!usb_init(pgm, pgm->usb_vid, pgm->usb_pid)) { 324 | fprintf(stderr, "Couldn't initialize stlink"); 325 | return false; 326 | } 327 | 328 | pgm->out_msg_size = 31; 329 | stlink_test_unit_ready(pgm); 330 | stlink_cmd(pgm, 0x06, buf, 0x80, 6, 0xf1, 0x80, 0x00, 0x00, 0x00, 0x00); 331 | stlink_test_unit_ready(pgm); 332 | stlink_cmd(pgm, 0x12, buf, 0x80, 6, 0x12, 0x80, 0x00, 0x00, 0x20); 333 | stlink_test_unit_ready(pgm); 334 | stlink_cmd(pgm, 2, buf, 0x80, 2, 0xf5, 0x00); // Reading status 335 | stlink_test_unit_ready(pgm); 336 | int status = unpack_int16_le(buf); 337 | switch(status) { 338 | case 0x0000: // Ok 339 | stlink_cmd(pgm, 0, NULL, 0x80, 2, 0xf3, 0x07); // Start initializing sequence 340 | stlink_cmd(pgm, 0, NULL, 0x00, 2, 0xf4, 0x00); // Turn the lights on 341 | stlink_cmd(pgm, 2, buf, 0x80, 2, 0xf4, 0x0d); 342 | stlink_cmd(pgm, 8, buf, 0x80, 3, 0xf4, 0x02, 0x01); // End init 343 | case 0x0003: // Already initialized 344 | return(true); 345 | case 0x0001: // Busy 346 | break; 347 | default: 348 | fprintf(stderr, "Unknown status: %x\n", status); 349 | } 350 | return(false); 351 | } 352 | 353 | void stlink_close(programmer_t *pgm) { 354 | libusb_exit(pgm->ctx); //close the session 355 | } 356 | 357 | void stlink_swim_srst(programmer_t *pgm) { 358 | // Ready bytes count (always 1 here) 359 | stlink_cmd(pgm, 0, NULL, 0x80, 0x0a, 360 | 0xf4, 0x08, 361 | 0x00, 0x01, 362 | 0x00, 0x00, 363 | 0x00, 0x00, 364 | 0x00, 0x00); 365 | stlink_swim_get_status(pgm); 366 | } 367 | 368 | int stlink_swim_write_byte(programmer_t *pgm, unsigned char byte, unsigned int start) { 369 | unsigned char buf[4], start2[2]; 370 | int result, tries = 0; 371 | pack_int16(start, start2); 372 | DEBUG_PRINT("stlink_swim_write_byte\n"); 373 | do { 374 | stlink_cmd(pgm, 0, NULL, 0x00, 0x10, 375 | 0xf4, 0x0a, 376 | 0x00, 0x01, 377 | 0x00, 0x00, 378 | start2[0], start2[1], 379 | byte, 0x00, 380 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); 381 | usleep(2000); 382 | // Ready bytes count (always 1 here) 383 | stlink_cmd(pgm, 4, buf, 0x80, 0x0a, 384 | 0xf4, 0x09, 385 | 0x00, 0x01, 386 | 0x00, 0x00, 387 | start2[0], start2[1], 388 | byte, 0x00); 389 | result = unpack_int16_le(buf); 390 | tries++; 391 | if(result & STLK_FLAG_BUFFER_FULL) { 392 | usleep(4000); // Chill out 393 | DEBUG_PRINT("retry\n"); 394 | continue; 395 | } 396 | if(result & STLK_FLAG_ERR) 397 | break; 398 | } while(result & STLK_FLAG_ERR && tries < 5); 399 | return(result); 400 | } 401 | 402 | int stlink_swim_read_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length) { 403 | unsigned char buf[4]; 404 | DEBUG_PRINT("stlink_swim_read_range\n"); 405 | stlink_init_session(pgm); 406 | stlink_swim_write_byte(pgm, 0x00, device->regs.CLK_CKDIVR); // mov 0x00, CLK_DIVR 407 | int i; 408 | for(i = 0; i < length; i += STLK_READ_BUFFER_SIZE) { 409 | unsigned char block_start2[2], block_size2[2]; 410 | int block_start = start + i; 411 | // Determining block size 412 | int block_size = length - i; 413 | if(block_size > STLK_READ_BUFFER_SIZE) 414 | block_size = STLK_READ_BUFFER_SIZE; 415 | DEBUG_PRINT("Reading %d bytes from %x\n", block_size, block_start); 416 | // Starting SWIM transfer 417 | pack_int16(block_start, block_start2); 418 | pack_int16(block_size, block_size2); 419 | stlink_cmd(pgm, 0, NULL, 0x80, 0x0a, 420 | 0xf4, 0x0b, 421 | block_size2[0], block_size2[1], 422 | 0x00, 0x00, 423 | block_start2[0], block_start2[1], 424 | 0x00, 0x00); 425 | // Waiting until the data becomes ready 426 | int result; 427 | do { 428 | usleep(2000); 429 | result = stlink_swim_get_status(pgm); 430 | } while(result & 1); 431 | // Downloading bytes from stlink 432 | stlink_cmd(pgm, block_size, &(buffer[i]), 0x80, 0x0a, 433 | 0xf4, 0x0c, 434 | block_size2[0], block_size2[1], 435 | 0x00, 0x00, 436 | block_start2[0], block_start2[1], 437 | 0x00, 0x00); 438 | } 439 | stlink_finish_session(pgm); 440 | return(length); 441 | } 442 | 443 | int stlink_swim_wait(programmer_t *pgm) { 444 | int result; 445 | do { 446 | usleep(3000); 447 | result = stlink_swim_get_status(pgm); 448 | } while(result & 1); 449 | return(result); 450 | } 451 | 452 | int stlink_swim_write_block(programmer_t *pgm, unsigned char *buffer, 453 | unsigned int start, 454 | unsigned int length, 455 | unsigned int padding 456 | ) { 457 | int length1 = 8 - padding; // Amount to be transferred with CBW 458 | int length2 = length - 8 + padding; // Amount to be transferred with additional transfer 459 | if (length2 < 0) length2 = 0; 460 | unsigned char block_size2[2], block_start2[2]; 461 | pack_int16(start, block_start2); 462 | pack_int16(length, block_size2); 463 | // Some logical checks 464 | assert(padding >= 0 && padding <= 1); 465 | assert(length1 + length2 == length); 466 | assert(length1 + padding <= 8); 467 | assert(length2 < STLK_MAX_WRITE - 6); 468 | assert(length1 > 0); 469 | assert(length2 > 0); 470 | // Filling CBW 471 | memset(&cbw, 0, sizeof(scsi_usb_cbw)); 472 | cbw.transfer_length = length2 + padding; 473 | cbw.flags = 0x00; 474 | cbw.cblength = 0x10; 475 | cbw.cb[0] = 0xf4; 476 | cbw.cb[1] = 0x0a; 477 | memcpy(cbw.cb+2, block_size2, 2); 478 | memcpy(cbw.cb+6, block_start2, 2); 479 | memcpy(cbw.cb+8+padding, buffer, length1); 480 | if(padding) cbw.cb[8] = '\0'; 481 | assert( stlink_send_cbw(DEV_HANDLE(pgm), &cbw) == 0); 482 | usleep(3000); 483 | if(length2) { 484 | // Sending the rest 485 | unsigned char tail[STLK_MAX_WRITE-6]; 486 | memcpy(tail, buffer + length1, length2); 487 | if(padding) tail[length2] = '\1'; 488 | int actual; 489 | int r = libusb_bulk_transfer(DEV_HANDLE(pgm), 490 | (2 | LIBUSB_ENDPOINT_OUT), 491 | tail, 492 | length2 + padding, 493 | &actual, 494 | 0); 495 | assert(actual == length2 + padding); 496 | } 497 | // Reading status 498 | stlink_read_csw(DEV_HANDLE(pgm), &csw); 499 | assert(csw.status == 0); 500 | memset(cbw.cb+8, 0, 8); 501 | cbw.cb[8] = 0x01; 502 | cbw.cb[9] = 0x02; 503 | int result = stlink_swim_wait(pgm); 504 | return(result); 505 | } 506 | 507 | int stlink_swim_write_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length, const memtype_t memtype) { 508 | int i; 509 | stlink_init_session(pgm); 510 | stlink_swim_write_byte(pgm, 0x00, device->regs.CLK_CKDIVR); 511 | if(memtype == FLASH || memtype == EEPROM || memtype == OPT) { 512 | stlink_swim_write_byte(pgm, 0x00, device->regs.FLASH_IAPSR); 513 | } 514 | if(memtype == FLASH) { 515 | stlink_swim_write_byte(pgm, 0x56, device->regs.FLASH_PUKR); 516 | stlink_swim_write_byte(pgm, 0xae, device->regs.FLASH_PUKR); 517 | } 518 | if(memtype == EEPROM || memtype == OPT) { 519 | stlink_swim_write_byte(pgm, 0xae, device->regs.FLASH_DUKR); 520 | stlink_swim_write_byte(pgm, 0x56, device->regs.FLASH_DUKR); 521 | } 522 | if(memtype == FLASH || memtype == EEPROM || memtype == OPT) { 523 | stlink_swim_write_byte(pgm, 0x56, device->regs.FLASH_IAPSR); 524 | } 525 | int flash_block_size = device->flash_block_size; 526 | for(i = 0; i < length; i+=flash_block_size) { 527 | unsigned char block[128]; 528 | memset(block, 0, sizeof(block)); 529 | int block_size = length - i; 530 | if(block_size > flash_block_size) 531 | block_size = flash_block_size; 532 | DEBUG_PRINT("Writing block %04x with size %d\n", start+i, block_size); 533 | memcpy(block, buffer+i, block_size); 534 | if(block_size < flash_block_size) { 535 | DEBUG_PRINT("Padding block %04x with %d zeroes\n", 536 | start+i, 537 | flash_block_size - block_size); 538 | block_size = flash_block_size; 539 | } 540 | if(memtype == FLASH || memtype == EEPROM || memtype == OPT) { 541 | stlink_swim_write_byte(pgm, 0x01, device->regs.FLASH_CR2); 542 | if(device->regs.FLASH_NCR2 != 0) { // Device have FLASH_NCR2 register 543 | stlink_swim_write_byte(pgm, 0xFE, device->regs.FLASH_NCR2); 544 | } 545 | } 546 | int result = stlink_swim_write_block(pgm, block, start + i, block_size, 0); 547 | if(result & STLK_FLAG_ERR) 548 | fprintf(stderr, "Write error\n"); 549 | } 550 | if(memtype == FLASH || memtype == EEPROM || memtype == OPT) { 551 | stlink_swim_write_byte(pgm, 0x56, device->regs.FLASH_IAPSR); 552 | } 553 | stlink_finish_session(pgm); 554 | return(length); 555 | } 556 | -------------------------------------------------------------------------------- /stlink.h: -------------------------------------------------------------------------------- 1 | /* stlink/v2 device driver 2 | (c) Valentin Dudouyt, 2012 */ 3 | 4 | #ifndef __STLINK_H 5 | #define __STLINK_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "pgm.h" 12 | 13 | typedef struct stlink_context_s { 14 | libusb_device_handle *dev_handle; 15 | libusb_context *ctx; 16 | unsigned int debug; 17 | } stlink_context_t; 18 | 19 | typedef enum { 20 | STLK_OK = 0, 21 | STLK_USB_ERROR, 22 | STLK_SWIM_ERROR 23 | } stlink_status_t; 24 | 25 | /* stlinkv1 uses the USB-TO-ATA protocol to communicate (same as your 26 | USB flash drive), with exception that some additional commands are 27 | supported */ 28 | #define USB_CBW_SIGNATURE 0x55534243 29 | #define USB_CBW_SIZE 31 30 | typedef struct _scsi_usb_cbw { 31 | // Command block warper 32 | uint32_t signature; // Always 0x55534243 33 | uint32_t tag; // Arbitrary value 34 | uint32_t transfer_length; 35 | unsigned char flags; 36 | unsigned char LUN; // SCSI drive identificator (always 0 here) 37 | unsigned char cblength; 38 | unsigned char cb[16]; // Raw command 39 | } scsi_usb_cbw; 40 | 41 | #define USB_CSW_SIZE 13 42 | typedef struct _scsi_usb_csw { 43 | // Command status warper 44 | uint32_t signature; // Always 0x55534243 45 | uint32_t tag; // Same as passed with CBW 46 | uint32_t data_residue; // cbw.transfer_length - actual handled 47 | unsigned char status; 48 | } scsi_usb_csw; 49 | 50 | bool stlink_open(programmer_t *pgm); 51 | void stlink_close(programmer_t *pgm); 52 | void stlink_swim_srst(programmer_t *pgm); 53 | int stlink_swim_read_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length); 54 | int stlink_swim_write_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length, const memtype_t memtype); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /stlinkv2.c: -------------------------------------------------------------------------------- 1 | /* stlink-v2 specific functions 2 | (c) Valentin Dudouyt, 2012-2013 */ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "stlink.h" 11 | #include "error.h" 12 | #include "try.h" 13 | #include "byte_utils.h" 14 | #include "stlinkv2.h" 15 | #include "usb.h" 16 | 17 | unsigned char *pack_int16(uint16_t word, unsigned char *out); 18 | 19 | #define STLK_READ_BUFFER_SIZE 6144 20 | 21 | unsigned char cmd_buf[16]; 22 | 23 | unsigned int stlink2_get_status(programmer_t *pgm); 24 | int stlink2_write_byte(programmer_t *pgm, unsigned char byte, unsigned int start); 25 | int stlink2_write_and_read_byte(programmer_t *pgm, unsigned char byte, unsigned int start); 26 | 27 | static unsigned int msg_transfer(programmer_t *pgm, unsigned char *buf, unsigned int length, int direction) { 28 | int bytes_transferred; 29 | int ep = (direction == LIBUSB_ENDPOINT_OUT) ? 2 : 1; 30 | libusb_bulk_transfer(DEV_HANDLE(pgm), ep | direction, buf, length, &bytes_transferred, 0); 31 | if(bytes_transferred != length) ERROR2("IO error: expected %d bytes but %d bytes transferred\n", length, bytes_transferred); 32 | return bytes_transferred; 33 | } 34 | 35 | static unsigned int msg_send(programmer_t *pgm, unsigned char *buf, unsigned int length) { 36 | return msg_transfer(pgm, buf, length, LIBUSB_ENDPOINT_OUT); 37 | } 38 | 39 | static unsigned int msg_recv(programmer_t *pgm, unsigned char *buf, unsigned int length) { 40 | return msg_transfer(pgm, buf, length, LIBUSB_ENDPOINT_IN); 41 | } 42 | 43 | static void msg_recv0(programmer_t *pgm, unsigned int length) { 44 | unsigned char buf[64]; 45 | msg_recv(pgm, buf, length); 46 | } 47 | 48 | static unsigned int msg_recv_int(programmer_t *pgm, unsigned int length) { 49 | unsigned char buf[4]; 50 | msg_recv(pgm, buf, length); 51 | return load_int(buf, length, MP_LITTLE_ENDIAN); 52 | } 53 | 54 | static unsigned int msg_recv_int8(programmer_t *pgm) { return msg_recv_int(pgm, 1); } 55 | static unsigned int msg_recv_int16(programmer_t *pgm) { return msg_recv_int(pgm, 2); } 56 | static unsigned int msg_recv_int32(programmer_t *pgm) { return msg_recv_int(pgm, 4); } 57 | 58 | static void msg_init(unsigned char *out, unsigned int cmd) { 59 | memset(out, 0, 16); 60 | format_int(out, cmd, 2, MP_BIG_ENDIAN); 61 | } 62 | 63 | static void stlink2_cmd(programmer_t *pgm, unsigned int cmd, unsigned int length, ...) { 64 | va_list ap; 65 | int i; 66 | 67 | // Preparing 68 | msg_init(cmd_buf, cmd); 69 | va_start(ap, length); 70 | for(i = 0; i < length; i++) { 71 | cmd_buf[i + 2] = va_arg(ap, int); 72 | } 73 | va_end(ap); 74 | 75 | // Triggering USB transfer 76 | msg_send(pgm, cmd_buf, sizeof(cmd_buf)); 77 | } 78 | 79 | bool stlink2_open(programmer_t *pgm) { 80 | if(!usb_init(pgm, pgm->usb_vid, pgm->usb_pid)) { 81 | fprintf(stderr, "Couldn't initialize stlink"); 82 | return false; 83 | } 84 | stlink2_cmd(pgm, 0xf500, 0); 85 | switch(msg_recv_int16(pgm)) { 86 | case 0x0100: 87 | case 0x0001: 88 | // Run initializing sequence 89 | stlink2_cmd(pgm, 0xf307, 0); // Start initializing sequence 90 | stlink2_cmd(pgm, 0xf400, 0); // Turns the lights on 91 | case 0x0003: 92 | stlink2_cmd(pgm, 0xf40d, 0); 93 | msg_recv_int16(pgm); 94 | stlink2_cmd(pgm, 0xf402, 1, 0x01); 95 | msg_recv0(pgm, 8); 96 | break; 97 | } 98 | return(true); 99 | } 100 | 101 | void stlink2_srst(programmer_t *pgm) { 102 | stlink2_cmd(pgm, 0xf407, 2, 0x00, 0x01); 103 | stlink2_get_status(pgm); 104 | stlink2_cmd(pgm, 0xf408, 2, 0x00, 0x01); 105 | stlink2_get_status(pgm); 106 | } 107 | 108 | void stlink2_init_session(programmer_t *pgm) { 109 | int i; 110 | char f4_cmd_arg1[] = { 0x07, 111 | 0x07, 112 | 0x08, 113 | 0x07, 114 | 0x04, 115 | 0x03, 116 | 0x05, 117 | }; 118 | for(i = 0; i < sizeof(f4_cmd_arg1); i++) { 119 | stlink2_cmd(pgm, 0xf400 | f4_cmd_arg1[i], 0); 120 | TRY(8, stlink2_get_status(pgm) == 0); 121 | } 122 | 123 | stlink2_write_byte(pgm, 0xa0, 0x7f80); // mov 0x0a, SWIM_CSR2 ;; Init SWIM 124 | stlink2_cmd(pgm, 0xf408, 0); 125 | TRY(8, stlink2_get_status(pgm) == 0); 126 | 127 | stlink2_write_and_read_byte(pgm, 0xa0, 0x7f99); 128 | stlink2_cmd(pgm, 0xf40c, 0); 129 | msg_recv_int8(pgm); // 0x08 (or 0x0a if used stlink2_write_byte() instead) 130 | } 131 | 132 | void stlink2_finish_session(programmer_t *pgm) { 133 | stlink2_cmd(pgm, 0xf405, 0); 134 | stlink2_get_status(pgm); 135 | stlink2_cmd(pgm, 0xf407, 0); 136 | stlink2_get_status(pgm); 137 | stlink2_cmd(pgm, 0xf403, 0); 138 | stlink2_get_status(pgm); 139 | } 140 | 141 | int stlink2_write_byte(programmer_t *pgm, unsigned char byte, unsigned int start) { 142 | unsigned char buf[4], start2[2]; 143 | pack_int16(start, start2); 144 | stlink2_cmd(pgm, 0xf40a, 7, 145 | 0x00, 0x01, 146 | 0x00, 0x00, 147 | HI(start), LO(start), 148 | byte); 149 | usleep(2000); 150 | return(stlink2_get_status(pgm)); // Should be '1' 151 | } 152 | 153 | int stlink2_write_word(programmer_t *pgm, unsigned int word, unsigned int start) { 154 | unsigned char buf[4], start2[2]; 155 | pack_int16(start, start2); 156 | stlink2_cmd(pgm, 0xf40a, 8, 157 | 0x00, 0x02, 158 | 0x00, 0x00, 159 | HI(start), LO(start), 160 | HI(word), LO(word)); 161 | usleep(2000); 162 | return(stlink2_get_status(pgm)); // Should be '1' 163 | } 164 | 165 | int stlink2_write_and_read_byte(programmer_t *pgm, unsigned char byte, unsigned int start) { 166 | unsigned char buf[4], start2[2]; 167 | pack_int16(start, start2); 168 | stlink2_cmd(pgm, 0xf40b, 7, 169 | 0x00, 0x01, 170 | 0x00, 0x00, 171 | HI(start), LO(start), 172 | byte); 173 | usleep(2000); 174 | stlink2_get_status(pgm); 175 | 176 | stlink2_cmd(pgm, 0xf40c, 0); 177 | return(msg_recv_int8(pgm)); 178 | } 179 | 180 | unsigned int stlink2_get_status(programmer_t *pgm) { 181 | stlink2_cmd(pgm, 0xf409, 0); 182 | return msg_recv_int32(pgm); 183 | } 184 | 185 | int stlink2_swim_read_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length) { 186 | stlink2_init_session(pgm); 187 | 188 | int i; 189 | for(i = 0; i < length; i += STLK_READ_BUFFER_SIZE) { 190 | // Determining current block start & size (relative to 0x8000) 191 | int block_start = start + i; 192 | int block_size = length - i; 193 | if(block_size > STLK_READ_BUFFER_SIZE) { 194 | block_size = STLK_READ_BUFFER_SIZE; 195 | } 196 | 197 | // Sending USB packet 198 | stlink2_cmd(pgm, 0xf40b, 6, 199 | HI(block_size), LO(block_size), 200 | 0x00, 0x00, 201 | HI(block_start), LO(block_start)); 202 | TRY(128, (stlink2_get_status(pgm) & 0xffff) == 0); 203 | 204 | // Seems like we've got some bytes from stlink, downloading them 205 | stlink2_cmd(pgm, 0xf40c, 0); 206 | msg_recv(pgm, &(buffer[i]), block_size); 207 | } 208 | 209 | return(length); 210 | } 211 | 212 | void stlink2_wait_until_transfer_completes(programmer_t *pgm, const stm8_device_t *device) { 213 | TRY(8, stlink2_write_and_read_byte(pgm, 0x82, device->regs.FLASH_IAPSR) & 0x4); 214 | } 215 | 216 | int stlink2_swim_write_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length, const memtype_t memtype) { 217 | stlink2_init_session(pgm); 218 | 219 | stlink2_write_byte(pgm, 0x00, device->regs.CLK_CKDIVR); 220 | if(memtype == FLASH || memtype == EEPROM || memtype == OPT) { 221 | stlink2_write_and_read_byte(pgm, 0x00, device->regs.FLASH_IAPSR); 222 | } 223 | 224 | // Unlock MASS 225 | if(memtype == FLASH) { 226 | stlink2_write_byte(pgm, 0x56, device->regs.FLASH_PUKR); 227 | stlink2_write_byte(pgm, 0xae, device->regs.FLASH_PUKR); 228 | } 229 | if(memtype == EEPROM || memtype == OPT) { 230 | stlink2_write_byte(pgm, 0xae, device->regs.FLASH_DUKR); 231 | stlink2_write_byte(pgm, 0x56, device->regs.FLASH_DUKR); 232 | } 233 | 234 | if(memtype == FLASH || memtype == EEPROM || memtype == OPT) { 235 | stlink2_write_and_read_byte(pgm, 0x56, device->regs.FLASH_IAPSR); // mov 0x56, FLASH_IAPSR 236 | } 237 | 238 | int i; 239 | int BLOCK_SIZE = device->flash_block_size; 240 | for(i = 0; i < length; i+=BLOCK_SIZE) { 241 | if(memtype == FLASH || memtype == EEPROM) { 242 | // block programming mode 243 | stlink2_write_byte(pgm, 0x01, device->regs.FLASH_CR2); // mov 0x01fe, FLASH_CR2; 0x817e - enable write OPT bytes 244 | if(device->regs.FLASH_NCR2 != 0) { // Device have FLASH_NCR2 register 245 | stlink2_write_byte(pgm, 0xFE, device->regs.FLASH_NCR2); 246 | } 247 | } else if (memtype == OPT){ 248 | // option programming mode 249 | stlink2_write_byte(pgm, 0x80, device->regs.FLASH_CR2); 250 | if(device->regs.FLASH_NCR2 != 0) { 251 | stlink2_write_byte(pgm, 0x7F, device->regs.FLASH_NCR2); 252 | } 253 | } 254 | 255 | if(memtype == OPT){ 256 | int j; 257 | for(j = 0; j < length; j++){ 258 | stlink2_write_byte(pgm, buffer[j], start+j); 259 | TRY(8, HI(stlink2_get_status(pgm)) == 1); 260 | } 261 | } else { 262 | // page-based writing 263 | // The first 8 packet bytes are getting transmitted 264 | // with the same USB bulk transfer as the command itself 265 | msg_init(cmd_buf, 0xf40a); 266 | format_int(&(cmd_buf[2]), BLOCK_SIZE, 2, MP_BIG_ENDIAN); 267 | format_int(&(cmd_buf[6]), start + i, 2, MP_BIG_ENDIAN); 268 | memcpy(&(cmd_buf[8]), &(buffer[i]), 8); 269 | msg_send(pgm, cmd_buf, sizeof(cmd_buf)); 270 | 271 | // Transmitting the rest 272 | msg_send(pgm, &(buffer[i + 8]), BLOCK_SIZE - 8); 273 | 274 | // Waiting for the transfer to process 275 | TRY(128, HI(stlink2_get_status(pgm)) == BLOCK_SIZE); 276 | } 277 | 278 | if(memtype == FLASH || memtype == EEPROM || memtype == OPT) { 279 | stlink2_wait_until_transfer_completes(pgm, device); 280 | } 281 | } 282 | if(memtype == FLASH || memtype == EEPROM || memtype == OPT) { 283 | stlink2_write_and_read_byte(pgm, 0x56, device->regs.FLASH_IAPSR); // mov 0x56, FLASH_IAPSR 284 | } 285 | stlink2_write_byte(pgm, 0x00, 0x7f80); 286 | stlink2_write_byte(pgm, 0xb6, 0x7f80); 287 | stlink2_finish_session(pgm); 288 | return(length); 289 | } 290 | 291 | -------------------------------------------------------------------------------- /stlinkv2.h: -------------------------------------------------------------------------------- 1 | #ifndef __STLINKV2_H 2 | #define __STLINKV2_H 3 | 4 | #include "pgm.h" 5 | 6 | bool stlink2_open(programmer_t *pgm); 7 | void stlink2_srst(programmer_t *pgm); 8 | int stlink2_swim_read_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length); 9 | int stlink2_swim_write_range(programmer_t *pgm, const stm8_device_t *device, unsigned char *buffer, unsigned int start, unsigned int length, const memtype_t memtype); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /stm8.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "stm8.h" 3 | 4 | #define REGS_STM8S { \ 5 | .CLK_CKDIVR = 0x50c6, \ 6 | .FLASH_PUKR = 0x5062, \ 7 | .FLASH_DUKR = 0x5064, \ 8 | .FLASH_IAPSR = 0x505f, \ 9 | .FLASH_CR2 = 0x505b, \ 10 | .FLASH_NCR2 = 0x505c, \ 11 | } 12 | 13 | // Note: FLASH_NCR2 not present on stm8l 14 | #define REGS_STM8L { \ 15 | .CLK_CKDIVR = 0x50c6, \ 16 | .FLASH_PUKR = 0x5052, \ 17 | .FLASH_DUKR = 0x5053, \ 18 | .FLASH_IAPSR = 0x5054, \ 19 | .FLASH_CR2 = 0x5051, \ 20 | .FLASH_NCR2 = 0x0000, \ 21 | } 22 | 23 | const stm8_device_t stm8_devices[] = { 24 | { 25 | .name = "stlux???a", 26 | .ram_start = 0x0000, 27 | .ram_size = 2*1024, 28 | .eeprom_start = 0x4000, 29 | .eeprom_size = 1024, 30 | .flash_start = 0x8000, 31 | .flash_size = 32*1024, 32 | .flash_block_size = 128, 33 | REGS_STM8S 34 | }, 35 | { 36 | .name = "stm8af526?", 37 | .ram_start = 0x0000, 38 | .ram_size = 6*1024, 39 | .eeprom_start = 0x4000, 40 | .eeprom_size = 1024, 41 | .flash_start = 0x8000, 42 | .flash_size = 32*1024, 43 | .flash_block_size = 128, 44 | REGS_STM8S 45 | }, 46 | { 47 | .name = "stm8af528?", 48 | .ram_start = 0x0000, 49 | .ram_size = 6*1024, 50 | .eeprom_start = 0x4000, 51 | .eeprom_size = 2048, 52 | .flash_start = 0x8000, 53 | .flash_size = 64*1024, 54 | .flash_block_size = 128, 55 | REGS_STM8S 56 | }, 57 | { 58 | .name = "stm8af52a?", 59 | .ram_start = 0x0000, 60 | .ram_size = 6*1024, 61 | .eeprom_start = 0x4000, 62 | .eeprom_size = 2048, 63 | .flash_start = 0x8000, 64 | .flash_size = 128*1024, 65 | .flash_block_size = 128, 66 | REGS_STM8S 67 | }, 68 | { 69 | .name = "stm8af6213", 70 | .ram_start = 0x0000, 71 | .ram_size = 1*1024, 72 | .eeprom_start = 0x4000, 73 | .eeprom_size = 640, 74 | .flash_start = 0x8000, 75 | .flash_size = 4*1024, 76 | .flash_block_size = 64, 77 | REGS_STM8S 78 | }, 79 | { 80 | .name = "stm8af6223", 81 | .ram_start = 0x0000, 82 | .ram_size = 1*1024, 83 | .eeprom_start = 0x4000, 84 | .eeprom_size = 640, 85 | .flash_start = 0x8000, 86 | .flash_size = 8*1024, 87 | .flash_block_size = 64, 88 | REGS_STM8S 89 | }, 90 | { 91 | .name = "stm8af6223a", 92 | .ram_start = 0x0000, 93 | .ram_size = 1*1024, 94 | .eeprom_start = 0x4000, 95 | .eeprom_size = 640, 96 | .flash_start = 0x8000, 97 | .flash_size = 8*1024, 98 | .flash_block_size = 64, 99 | REGS_STM8S 100 | }, 101 | { 102 | .name = "stm8af6226", 103 | .ram_start = 0x0000, 104 | .ram_size = 2*1024, 105 | .eeprom_start = 0x4000, 106 | .eeprom_size = 640, 107 | .flash_start = 0x8000, 108 | .flash_size = 8*1024, 109 | .flash_block_size = 64, 110 | REGS_STM8S 111 | }, 112 | { 113 | .name = "stm8af624?", 114 | .ram_start = 0x0000, 115 | .ram_size = 2*1024, 116 | .eeprom_start = 0x4000, 117 | .eeprom_size = 512, 118 | .flash_start = 0x8000, 119 | .flash_size = 16*1024, 120 | .flash_block_size = 128, 121 | REGS_STM8S 122 | }, 123 | { 124 | .name = "stm8af6266", 125 | .ram_start = 0x0000, 126 | .ram_size = 2*1024, 127 | .eeprom_start = 0x4000, 128 | .eeprom_size = 1024, 129 | .flash_start = 0x8000, 130 | .flash_size = 32*1024, 131 | .flash_block_size = 128, 132 | REGS_STM8S 133 | }, 134 | { 135 | .name = "stm8af6268", 136 | .ram_start = 0x0000, 137 | .ram_size = 2*1024, 138 | .eeprom_start = 0x4000, 139 | .eeprom_size = 1024, 140 | .flash_start = 0x8000, 141 | .flash_size = 32*1024, 142 | .flash_block_size = 128, 143 | REGS_STM8S 144 | }, 145 | { 146 | .name = "stm8af6269", 147 | .ram_start = 0x0000, 148 | .ram_size = 6*1024, 149 | .eeprom_start = 0x4000, 150 | .eeprom_size = 1024, 151 | .flash_start = 0x8000, 152 | .flash_size = 32*1024, 153 | .flash_block_size = 128, 154 | REGS_STM8S 155 | }, 156 | { 157 | .name = "stm8af628?", 158 | .ram_start = 0x0000, 159 | .ram_size = 6*1024, 160 | .eeprom_start = 0x4000, 161 | .eeprom_size = 2048, 162 | .flash_start = 0x8000, 163 | .flash_size = 64*1024, 164 | .flash_block_size = 128, 165 | REGS_STM8S 166 | }, 167 | { 168 | .name = "stm8af62a?", 169 | .ram_start = 0x0000, 170 | .ram_size = 6*1024, 171 | .eeprom_start = 0x4000, 172 | .eeprom_size = 2048, 173 | .flash_start = 0x8000, 174 | .flash_size = 128*1024, 175 | .flash_block_size = 128, 176 | REGS_STM8S 177 | }, 178 | { 179 | .name = "stm8al313?", 180 | .ram_start = 0x0000, 181 | .ram_size = 2*1024, 182 | .eeprom_start = 0x1000, 183 | .eeprom_size = 1024, 184 | .flash_start = 0x8000, 185 | .flash_size = 8*1024, 186 | .flash_block_size = 128, 187 | REGS_STM8L 188 | }, 189 | { 190 | .name = "stm8al314?", 191 | .ram_start = 0x0000, 192 | .ram_size = 2*1024, 193 | .eeprom_start = 0x1000, 194 | .eeprom_size = 1024, 195 | .flash_start = 0x8000, 196 | .flash_size = 16*1024, 197 | .flash_block_size = 128, 198 | REGS_STM8L 199 | }, 200 | { 201 | .name = "stm8al316?", 202 | .ram_start = 0x0000, 203 | .ram_size = 2*1024, 204 | .eeprom_start = 0x1000, 205 | .eeprom_size = 1024, 206 | .flash_start = 0x8000, 207 | .flash_size = 32*1024, 208 | .flash_block_size = 128, 209 | REGS_STM8L 210 | }, 211 | { 212 | .name = "stm8al3l4?", 213 | .ram_start = 0x0000, 214 | .ram_size = 2*1024, 215 | .eeprom_start = 0x1000, 216 | .eeprom_size = 1024, 217 | .flash_start = 0x8000, 218 | .flash_size = 16*1024, 219 | .flash_block_size = 128, 220 | REGS_STM8L 221 | }, 222 | { 223 | .name = "stm8al3l6?", 224 | .ram_start = 0x0000, 225 | .ram_size = 2*1024, 226 | .eeprom_start = 0x1000, 227 | .eeprom_size = 1024, 228 | .flash_start = 0x8000, 229 | .flash_size = 32*1024, 230 | .flash_block_size = 128, 231 | REGS_STM8L 232 | }, 233 | { 234 | .name = "stm8l051f3", 235 | .ram_start = 0x0000, 236 | .ram_size = 1*1024, 237 | .eeprom_start = 0x1000, 238 | .eeprom_size = 256, 239 | .flash_start = 0x8000, 240 | .flash_size = 8*1024, 241 | .flash_block_size = 64, 242 | REGS_STM8L 243 | }, 244 | { 245 | .name = "stm8l052c6", 246 | .ram_start = 0x0000, 247 | .ram_size = 2*1024, 248 | .eeprom_start = 0x1000, 249 | .eeprom_size = 256, 250 | .flash_start = 0x8000, 251 | .flash_size = 32*1024, 252 | .flash_block_size = 64, 253 | REGS_STM8L 254 | }, 255 | { 256 | .name = "stm8l052r8", 257 | .ram_start = 0x0000, 258 | .ram_size = 4*1024, 259 | .eeprom_start = 0x1000, 260 | .eeprom_size = 256, 261 | .flash_start = 0x8000, 262 | .flash_size = 64*1024, 263 | .flash_block_size = 64, 264 | REGS_STM8L 265 | }, 266 | { 267 | .name = "stm8l101f1", 268 | .ram_start = 0x0000, 269 | .ram_size = 0x05FF, 270 | .eeprom_start = 0x9FFF, // Overlapping flash and eeprom 271 | .eeprom_size = 0, 272 | .flash_start = 0x8000, 273 | .flash_size = 2*1024, 274 | .flash_block_size = 64, 275 | REGS_STM8L 276 | }, 277 | { 278 | .name = "stm8l101?2", 279 | .ram_start = 0x0000, 280 | .ram_size = 0x05FF, 281 | .eeprom_start = 0x9FFF, // Overlapping flash and eeprom 282 | .eeprom_size = 0, 283 | .flash_start = 0x8000, 284 | .flash_size = 4*1024, 285 | .flash_block_size = 64, 286 | REGS_STM8L 287 | }, 288 | { 289 | .name = "stm8l101?3", 290 | .ram_start = 0x0000, 291 | .ram_size = 0x05FF, 292 | .eeprom_start = 0x9FFF, // Overlapping flash and eeprom 293 | .eeprom_size = 0, 294 | .flash_start = 0x8000, 295 | .flash_size = 8*1024, 296 | .flash_block_size = 64, 297 | REGS_STM8L 298 | }, 299 | { 300 | .name = "stm8l151?2", 301 | .ram_start = 0x0000, 302 | .ram_size = 1*1024, 303 | .eeprom_start = 0x1000, 304 | .eeprom_size = 256, 305 | .flash_start = 0x8000, 306 | .flash_size = 4*1024, 307 | .flash_block_size = 64, 308 | REGS_STM8L 309 | }, 310 | { 311 | .name = "stm8l151?3", 312 | .ram_start = 0x0000, 313 | .ram_size = 1*1024, 314 | .eeprom_start = 0x1000, 315 | .eeprom_size = 256, 316 | .flash_start = 0x8000, 317 | .flash_size = 8*1024, 318 | .flash_block_size = 64, 319 | REGS_STM8L 320 | }, 321 | { 322 | .name = "stm8l151?4", 323 | .ram_start = 0x0000, 324 | .ram_size = 2*1024, 325 | .eeprom_start = 0x1000, 326 | .eeprom_size = 1024, 327 | .flash_start = 0x8000, 328 | .flash_size = 16*1024, 329 | .flash_block_size = 64, 330 | REGS_STM8L 331 | }, 332 | { 333 | .name = "stm8l151?6", 334 | .ram_start = 0x0000, 335 | .ram_size = 2*1024, 336 | .eeprom_start = 0x1000, 337 | .eeprom_size = 1024, 338 | .flash_start = 0x8000, 339 | .flash_size = 32*1024, 340 | .flash_block_size = 128, 341 | REGS_STM8L 342 | }, 343 | { 344 | .name = "stm8l151?8", 345 | .ram_start = 0x0000, 346 | .ram_size = 4*1024, 347 | .eeprom_start = 0x1000, 348 | .eeprom_size = 2048, 349 | .flash_start = 0x8000, 350 | .flash_size = 64*1024, 351 | .flash_block_size = 128, 352 | REGS_STM8L 353 | }, 354 | { 355 | .name = "stm8l152?4", 356 | .ram_start = 0x0000, 357 | .ram_size = 2*1024, 358 | .eeprom_start = 0x1000, 359 | .eeprom_size = 1024, 360 | .flash_start = 0x8000, 361 | .flash_size = 16*1024, 362 | .flash_block_size = 64, 363 | REGS_STM8L 364 | }, 365 | { 366 | .name = "stm8l152?6", 367 | .ram_start = 0x0000, 368 | .ram_size = 2*1024, 369 | .eeprom_start = 0x1000, 370 | .eeprom_size = 1024, 371 | .flash_start = 0x8000, 372 | .flash_size = 32*1024, 373 | .flash_block_size = 128, 374 | REGS_STM8L 375 | }, 376 | { 377 | .name = "stm8l152?8", 378 | .ram_start = 0x0000, 379 | .ram_size = 4*1024, 380 | .eeprom_start = 0x1000, 381 | .eeprom_size = 2048, 382 | .flash_start = 0x8000, 383 | .flash_size = 64*1024, 384 | .flash_block_size = 128, 385 | REGS_STM8L 386 | }, 387 | { 388 | .name = "stm8l162?8", 389 | .ram_start = 0x0000, 390 | .ram_size = 2*1024, 391 | .eeprom_start = 0x1000, 392 | .eeprom_size = 2048, 393 | .flash_start = 0x8000, 394 | .flash_size = 64*1024, 395 | .flash_block_size = 128, 396 | REGS_STM8L 397 | }, 398 | { 399 | .name = "stm8s003?3", 400 | .ram_start = 0x0000, 401 | .ram_size = 1*1024, 402 | .eeprom_start = 0x4000, 403 | .eeprom_size = 128, 404 | .flash_start = 0x8000, 405 | .flash_size = 8*1024, 406 | .flash_block_size = 64, 407 | REGS_STM8S 408 | }, 409 | { 410 | .name = "stm8s005?6", 411 | .ram_start = 0x0000, 412 | .ram_size = 2*1024, 413 | .eeprom_start = 0x4000, 414 | .eeprom_size = 128, 415 | .flash_start = 0x8000, 416 | .flash_size = 32*1024, 417 | .flash_block_size = 128, 418 | REGS_STM8S 419 | }, 420 | { 421 | .name = "stm8s007c8", 422 | .ram_start = 0x0000, 423 | .ram_size = 6*1024, 424 | .eeprom_start = 0x4000, 425 | .eeprom_size = 128, 426 | .flash_start = 0x8000, 427 | .flash_size = 64*1024, 428 | .flash_block_size = 128, 429 | REGS_STM8S 430 | }, 431 | { 432 | .name = "stm8s103f2", 433 | .ram_start = 0x0000, 434 | .ram_size = 1*1024, 435 | .eeprom_start = 0x4000, 436 | .eeprom_size = 640, 437 | .flash_start = 0x8000, 438 | .flash_size = 4*1024, 439 | .flash_block_size = 64, 440 | REGS_STM8S 441 | }, 442 | { 443 | .name = "stm8s103?3", 444 | .ram_start = 0x0000, 445 | .ram_size = 1*1024, 446 | .eeprom_start = 0x4000, 447 | .eeprom_size = 640, 448 | .flash_start = 0x8000, 449 | .flash_size = 8*1024, 450 | .flash_block_size = 64, 451 | REGS_STM8S 452 | }, 453 | { 454 | .name = "stm8s105?4", 455 | .ram_start = 0x0000, 456 | .ram_size = 2*1024, 457 | .eeprom_start = 0x4000, 458 | .eeprom_size = 1024, 459 | .flash_start = 0x8000, 460 | .flash_size = 16*1024, 461 | .flash_block_size = 128, 462 | REGS_STM8S 463 | }, 464 | { 465 | .name = "stm8s105?6", 466 | .ram_start = 0x0000, 467 | .ram_size = 2*1024, 468 | .eeprom_start = 0x4000, 469 | .eeprom_size = 1024, 470 | .flash_start = 0x8000, 471 | .flash_size = 32*1024, 472 | .flash_block_size = 128, 473 | REGS_STM8S 474 | }, 475 | { 476 | .name = "stm8s207c8", 477 | .ram_start = 0x0000, 478 | .ram_size = 6*1024, 479 | .eeprom_start = 0x4000, 480 | .eeprom_size = 1536, 481 | .flash_start = 0x8000, 482 | .flash_size = 64*1024, 483 | .flash_block_size = 128, 484 | REGS_STM8S 485 | }, 486 | { 487 | .name = "stm8s207cb", 488 | .ram_start = 0x0000, 489 | .ram_size = 6*1024, 490 | .eeprom_start = 0x4000, 491 | .eeprom_size = 2048, 492 | .flash_start = 0x8000, 493 | .flash_size = 128*1024, 494 | .flash_block_size = 128, 495 | REGS_STM8S 496 | }, 497 | { 498 | .name = "stm8s207k8", 499 | .ram_start = 0x0000, 500 | .ram_size = 6*1024, 501 | .eeprom_start = 0x4000, 502 | .eeprom_size = 1024, 503 | .flash_start = 0x8000, 504 | .flash_size = 64*1024, 505 | .flash_block_size = 128, 506 | REGS_STM8S 507 | }, 508 | { 509 | .name = "stm8s207m8", 510 | .ram_start = 0x0000, 511 | .ram_size = 6*1024, 512 | .eeprom_start = 0x4000, 513 | .eeprom_size = 2048, 514 | .flash_start = 0x8000, 515 | .flash_size = 64*1024, 516 | .flash_block_size = 128, 517 | REGS_STM8S 518 | }, 519 | { 520 | .name = "stm8s207mb", 521 | .ram_start = 0x0000, 522 | .ram_size = 6*1024, 523 | .eeprom_start = 0x4000, 524 | .eeprom_size = 2048, 525 | .flash_start = 0x8000, 526 | .flash_size = 128*1024, 527 | .flash_block_size = 128, 528 | REGS_STM8S 529 | }, 530 | { 531 | .name = "stm8s207r8", 532 | .ram_start = 0x0000, 533 | .ram_size = 6*1024, 534 | .eeprom_start = 0x4000, 535 | .eeprom_size = 1536, 536 | .flash_start = 0x8000, 537 | .flash_size = 64*1024, 538 | .flash_block_size = 128, 539 | REGS_STM8S 540 | }, 541 | { 542 | .name = "stm8s207rb", 543 | .ram_start = 0x0000, 544 | .ram_size = 6*1024, 545 | .eeprom_start = 0x4000, 546 | .eeprom_size = 2048, 547 | .flash_start = 0x8000, 548 | .flash_size = 128*1024, 549 | .flash_block_size = 128, 550 | REGS_STM8S 551 | }, 552 | { 553 | .name = "stm8s207s8", 554 | .ram_start = 0x0000, 555 | .ram_size = 6*1024, 556 | .eeprom_start = 0x4000, 557 | .eeprom_size = 1536, 558 | .flash_start = 0x8000, 559 | .flash_size = 64*1024, 560 | .flash_block_size = 128, 561 | REGS_STM8S 562 | }, 563 | { 564 | .name = "stm8s207sb", 565 | .ram_start = 0x0000, 566 | .ram_size = 6*1024, 567 | .eeprom_start = 0x4000, 568 | .eeprom_size = 1536, 569 | .flash_start = 0x8000, 570 | .flash_size = 128*1024, 571 | .flash_block_size = 128, 572 | REGS_STM8S 573 | }, 574 | { 575 | .name = "stm8s207?6", 576 | .ram_start = 0x0000, 577 | .ram_size = 6*1024, 578 | .eeprom_start = 0x4000, 579 | .eeprom_size = 1024, 580 | .flash_start = 0x8000, 581 | .flash_size = 32*1024, 582 | .flash_block_size = 128, 583 | REGS_STM8S 584 | }, 585 | { 586 | .name = "stm8s208c6", 587 | .ram_start = 0x0000, 588 | .ram_size = 6*1024, 589 | .eeprom_start = 0x4000, 590 | .eeprom_size = 2048, 591 | .flash_start = 0x8000, 592 | .flash_size = 32*1024, 593 | .flash_block_size = 128, 594 | REGS_STM8S 595 | }, 596 | { 597 | .name = "stm8s208s6", 598 | .ram_start = 0x0000, 599 | .ram_size = 6*1024, 600 | .eeprom_start = 0x4000, 601 | .eeprom_size = 1536, 602 | .flash_start = 0x8000, 603 | .flash_size = 32*1024, 604 | .flash_block_size = 128, 605 | REGS_STM8S 606 | }, 607 | { 608 | .name = "stm8s208?8", 609 | .ram_start = 0x0000, 610 | .ram_size = 6*1024, 611 | .eeprom_start = 0x4000, 612 | .eeprom_size = 2048, 613 | .flash_start = 0x8000, 614 | .flash_size = 64*1024, 615 | .flash_block_size = 128, 616 | REGS_STM8S 617 | }, 618 | { 619 | .name = "stm8s208?b", 620 | .ram_start = 0x0000, 621 | .ram_size = 6*1024, 622 | .eeprom_start = 0x4000, 623 | .eeprom_size = 2048, 624 | .flash_start = 0x8000, 625 | .flash_size = 128*1024, 626 | .flash_block_size = 128, 627 | REGS_STM8S 628 | }, 629 | { 630 | .name = "stm8s903?3", 631 | .ram_start = 0x0000, 632 | .ram_size = 1*1024, 633 | .eeprom_start = 0x4000, 634 | .eeprom_size = 640, 635 | .flash_start = 0x8000, 636 | .flash_size = 8*1024, 637 | .flash_block_size = 128, 638 | REGS_STM8S 639 | }, 640 | { 641 | .name = "stm8splnb1", 642 | .ram_start = 0x0000, 643 | .ram_size = 1*1024, 644 | .eeprom_start = 0x4000, 645 | .eeprom_size = 640, 646 | .flash_start = 0x8000, 647 | .flash_size = 8*1024, 648 | .flash_block_size = 128, 649 | REGS_STM8S 650 | }, 651 | { 652 | .name = "stm8tl5??4", 653 | .ram_start = 0x0000, 654 | .ram_size = 4096, 655 | .eeprom_start = 0x9FFF, // Overlapping flash and eeprom 656 | .eeprom_size = 0, 657 | .flash_start = 0x8000, 658 | .flash_size = 16*1024, 659 | .flash_block_size = 64, 660 | REGS_STM8L 661 | }, 662 | { 663 | .name = "stnrg???a", 664 | .ram_start = 0x0000, 665 | .ram_size = 6*1024, 666 | .eeprom_start = 0x4000, 667 | .eeprom_size = 1024, 668 | .flash_start = 0x8000, 669 | .flash_size = 32*1024, 670 | .flash_block_size = 128, 671 | REGS_STM8S 672 | }, 673 | { NULL }, 674 | }; 675 | 676 | -------------------------------------------------------------------------------- /stm8.h: -------------------------------------------------------------------------------- 1 | #ifndef __STM8_H 2 | #define __STM8_H 3 | 4 | /* This header file contains the generic information 5 | about supported STM8 devices */ 6 | 7 | typedef struct stm8_regs { 8 | unsigned int CLK_CKDIVR; 9 | unsigned int FLASH_PUKR; 10 | unsigned int FLASH_DUKR; 11 | unsigned int FLASH_IAPSR; 12 | unsigned int FLASH_CR2; 13 | unsigned int FLASH_NCR2; 14 | } stm8_regs_t; 15 | 16 | typedef struct stm8_device { 17 | const char *name; 18 | unsigned int ram_start; 19 | unsigned int ram_size; 20 | unsigned int eeprom_start; 21 | unsigned int eeprom_size; 22 | unsigned int flash_start; 23 | unsigned int flash_size; 24 | unsigned int flash_block_size; 25 | stm8_regs_t regs; 26 | } stm8_device_t; 27 | 28 | extern const stm8_device_t stm8_devices[]; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /try.h: -------------------------------------------------------------------------------- 1 | #define TRY(times, statement) do { \ 2 | int c = (times); \ 3 | while(c > 0) { \ 4 | usleep(3000); \ 5 | if((statement)) break; \ 6 | c--; \ 7 | } \ 8 | if(!c) { \ 9 | ERROR("Tries exceeded"); \ 10 | } \ 11 | } while(0) 12 | -------------------------------------------------------------------------------- /usb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "pgm.h" 9 | #include "usb.h" 10 | 11 | bool usb_init(programmer_t *pgm, unsigned int vid, unsigned int pid) { 12 | libusb_device **devs; 13 | libusb_context *ctx = NULL; 14 | 15 | int r; 16 | ssize_t cnt; 17 | r = libusb_init(&ctx); 18 | if(r < 0) return(false); 19 | 20 | libusb_set_debug(ctx, 3); 21 | cnt = libusb_get_device_list(ctx, &devs); 22 | if(cnt < 0) return(false); 23 | 24 | usb_context_t *uctx = malloc(sizeof(usb_context_t)); 25 | uctx->dev_handle = libusb_open_device_with_vid_pid(ctx, vid, pid); 26 | assert(uctx->dev_handle); 27 | uctx->ctx = ctx; 28 | pgm->ctx = uctx; 29 | 30 | libusb_free_device_list(devs, 1); //free the list, unref the devices in it 31 | 32 | if(libusb_kernel_driver_active(uctx->dev_handle, 0) == 1) { //find out if kernel driver is attached 33 | int r = libusb_detach_kernel_driver(uctx->dev_handle, 0); 34 | assert(r == 0); 35 | } 36 | 37 | #ifdef __APPLE__ 38 | r = libusb_claim_interface(uctx->dev_handle, 0); 39 | assert(r == 0); 40 | #endif 41 | 42 | return(true); 43 | } 44 | 45 | void usb_close(programmer_t *pgm) 46 | { 47 | // TODO release resources 48 | } 49 | -------------------------------------------------------------------------------- /usb.h: -------------------------------------------------------------------------------- 1 | #ifndef __USB_H 2 | #define __USB_H 3 | #include 4 | 5 | typedef struct usb_context_s { 6 | libusb_device_handle *dev_handle; 7 | libusb_context *ctx; 8 | } usb_context_t; 9 | 10 | bool usb_init(programmer_t *pgm, unsigned int vid, unsigned int pid); 11 | void usb_close(programmer_t *pgm); 12 | 13 | #define DEV_HANDLE(pgm) (((usb_context_t*)(pgm->ctx))->dev_handle) 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTILS_H 2 | #define __UTILS_H 3 | 4 | #ifdef DEBUG 5 | #define DEBUG_PRINT(...) do{ fprintf( stderr, __VA_ARGS__ ); } while( false ) 6 | #else 7 | #define DEBUG_PRINT(...) do{ } while ( false ) 8 | #endif 9 | 10 | #endif 11 | --------------------------------------------------------------------------------