├── COPYRIGHT ├── Makefile ├── README ├── cli.c ├── cli.h ├── dial.c ├── dial.h ├── flash.c ├── flash.h ├── keypad.c ├── keypad.h ├── lcd.c ├── lcd.h ├── main.c ├── stepper.c ├── stepper.h ├── timer.c ├── timer.h ├── usb.c ├── usb.h └── version.h /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright 2010 2 | 3 | Freecut is free software: you can redistribute it and/or modify it 4 | under the terms of the GNU General Public License version 2. 5 | 6 | Freecut is distributed in the hope that it will be useful, but WITHOUT 7 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 8 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 9 | License for more details. 10 | 11 | You should have received a copy of the GNU General Public License 12 | along with Freecut. If not, see http://www.gnu.org/licenses/. 13 | 14 | ---------------------------------------------------------------------- 15 | 16 | 17 | GNU GENERAL PUBLIC LICENSE 18 | Version 2, June 1991 19 | 20 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | Everyone is permitted to copy and distribute verbatim copies 23 | of this license document, but changing it is not allowed. 24 | 25 | Preamble 26 | 27 | The licenses for most software are designed to take away your 28 | freedom to share and change it. By contrast, the GNU General Public 29 | License is intended to guarantee your freedom to share and change free 30 | software--to make sure the software is free for all its users. This 31 | General Public License applies to most of the Free Software 32 | Foundation's software and to any other program whose authors commit to 33 | using it. (Some other Free Software Foundation software is covered by 34 | the GNU Lesser General Public License instead.) You can apply it to 35 | your programs, too. 36 | 37 | When we speak of free software, we are referring to freedom, not 38 | price. Our General Public Licenses are designed to make sure that you 39 | have the freedom to distribute copies of free software (and charge for 40 | this service if you wish), that you receive source code or can get it 41 | if you want it, that you can change the software or use pieces of it 42 | in new free programs; and that you know you can do these things. 43 | 44 | To protect your rights, we need to make restrictions that forbid 45 | anyone to deny you these rights or to ask you to surrender the rights. 46 | These restrictions translate to certain responsibilities for you if you 47 | distribute copies of the software, or if you modify it. 48 | 49 | For example, if you distribute copies of such a program, whether 50 | gratis or for a fee, you must give the recipients all the rights that 51 | you have. You must make sure that they, too, receive or can get the 52 | source code. And you must show them these terms so they know their 53 | rights. 54 | 55 | We protect your rights with two steps: (1) copyright the software, and 56 | (2) offer you this license which gives you legal permission to copy, 57 | distribute and/or modify the software. 58 | 59 | Also, for each author's protection and ours, we want to make certain 60 | that everyone understands that there is no warranty for this free 61 | software. If the software is modified by someone else and passed on, we 62 | want its recipients to know that what they have is not the original, so 63 | that any problems introduced by others will not reflect on the original 64 | authors' reputations. 65 | 66 | Finally, any free program is threatened constantly by software 67 | patents. We wish to avoid the danger that redistributors of a free 68 | program will individually obtain patent licenses, in effect making the 69 | program proprietary. To prevent this, we have made it clear that any 70 | patent must be licensed for everyone's free use or not licensed at all. 71 | 72 | The precise terms and conditions for copying, distribution and 73 | modification follow. 74 | 75 | GNU GENERAL PUBLIC LICENSE 76 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 77 | 78 | 0. This License applies to any program or other work which contains 79 | a notice placed by the copyright holder saying it may be distributed 80 | under the terms of this General Public License. The "Program", below, 81 | refers to any such program or work, and a "work based on the Program" 82 | means either the Program or any derivative work under copyright law: 83 | that is to say, a work containing the Program or a portion of it, 84 | either verbatim or with modifications and/or translated into another 85 | language. (Hereinafter, translation is included without limitation in 86 | the term "modification".) Each licensee is addressed as "you". 87 | 88 | Activities other than copying, distribution and modification are not 89 | covered by this License; they are outside its scope. The act of 90 | running the Program is not restricted, and the output from the Program 91 | is covered only if its contents constitute a work based on the 92 | Program (independent of having been made by running the Program). 93 | Whether that is true depends on what the Program does. 94 | 95 | 1. You may copy and distribute verbatim copies of the Program's 96 | source code as you receive it, in any medium, provided that you 97 | conspicuously and appropriately publish on each copy an appropriate 98 | copyright notice and disclaimer of warranty; keep intact all the 99 | notices that refer to this License and to the absence of any warranty; 100 | and give any other recipients of the Program a copy of this License 101 | along with the Program. 102 | 103 | You may charge a fee for the physical act of transferring a copy, and 104 | you may at your option offer warranty protection in exchange for a fee. 105 | 106 | 2. You may modify your copy or copies of the Program or any portion 107 | of it, thus forming a work based on the Program, and copy and 108 | distribute such modifications or work under the terms of Section 1 109 | above, provided that you also meet all of these conditions: 110 | 111 | a) You must cause the modified files to carry prominent notices 112 | stating that you changed the files and the date of any change. 113 | 114 | b) You must cause any work that you distribute or publish, that in 115 | whole or in part contains or is derived from the Program or any 116 | part thereof, to be licensed as a whole at no charge to all third 117 | parties under the terms of this License. 118 | 119 | c) If the modified program normally reads commands interactively 120 | when run, you must cause it, when started running for such 121 | interactive use in the most ordinary way, to print or display an 122 | announcement including an appropriate copyright notice and a 123 | notice that there is no warranty (or else, saying that you provide 124 | a warranty) and that users may redistribute the program under 125 | these conditions, and telling the user how to view a copy of this 126 | License. (Exception: if the Program itself is interactive but 127 | does not normally print such an announcement, your work based on 128 | the Program is not required to print an announcement.) 129 | 130 | These requirements apply to the modified work as a whole. If 131 | identifiable sections of that work are not derived from the Program, 132 | and can be reasonably considered independent and separate works in 133 | themselves, then this License, and its terms, do not apply to those 134 | sections when you distribute them as separate works. But when you 135 | distribute the same sections as part of a whole which is a work based 136 | on the Program, the distribution of the whole must be on the terms of 137 | this License, whose permissions for other licensees extend to the 138 | entire whole, and thus to each and every part regardless of who wrote it. 139 | 140 | Thus, it is not the intent of this section to claim rights or contest 141 | your rights to work written entirely by you; rather, the intent is to 142 | exercise the right to control the distribution of derivative or 143 | collective works based on the Program. 144 | 145 | In addition, mere aggregation of another work not based on the Program 146 | with the Program (or with a work based on the Program) on a volume of 147 | a storage or distribution medium does not bring the other work under 148 | the scope of this License. 149 | 150 | 3. You may copy and distribute the Program (or a work based on it, 151 | under Section 2) in object code or executable form under the terms of 152 | Sections 1 and 2 above provided that you also do one of the following: 153 | 154 | a) Accompany it with the complete corresponding machine-readable 155 | source code, which must be distributed under the terms of Sections 156 | 1 and 2 above on a medium customarily used for software interchange; or, 157 | 158 | b) Accompany it with a written offer, valid for at least three 159 | years, to give any third party, for a charge no more than your 160 | cost of physically performing source distribution, a complete 161 | machine-readable copy of the corresponding source code, to be 162 | distributed under the terms of Sections 1 and 2 above on a medium 163 | customarily used for software interchange; or, 164 | 165 | c) Accompany it with the information you received as to the offer 166 | to distribute corresponding source code. (This alternative is 167 | allowed only for noncommercial distribution and only if you 168 | received the program in object code or executable form with such 169 | an offer, in accord with Subsection b above.) 170 | 171 | The source code for a work means the preferred form of the work for 172 | making modifications to it. For an executable work, complete source 173 | code means all the source code for all modules it contains, plus any 174 | associated interface definition files, plus the scripts used to 175 | control compilation and installation of the executable. However, as a 176 | special exception, the source code distributed need not include 177 | anything that is normally distributed (in either source or binary 178 | form) with the major components (compiler, kernel, and so on) of the 179 | operating system on which the executable runs, unless that component 180 | itself accompanies the executable. 181 | 182 | If distribution of executable or object code is made by offering 183 | access to copy from a designated place, then offering equivalent 184 | access to copy the source code from the same place counts as 185 | distribution of the source code, even though third parties are not 186 | compelled to copy the source along with the object code. 187 | 188 | 4. You may not copy, modify, sublicense, or distribute the Program 189 | except as expressly provided under this License. Any attempt 190 | otherwise to copy, modify, sublicense or distribute the Program is 191 | void, and will automatically terminate your rights under this License. 192 | However, parties who have received copies, or rights, from you under 193 | this License will not have their licenses terminated so long as such 194 | parties remain in full compliance. 195 | 196 | 5. You are not required to accept this License, since you have not 197 | signed it. However, nothing else grants you permission to modify or 198 | distribute the Program or its derivative works. These actions are 199 | prohibited by law if you do not accept this License. Therefore, by 200 | modifying or distributing the Program (or any work based on the 201 | Program), you indicate your acceptance of this License to do so, and 202 | all its terms and conditions for copying, distributing or modifying 203 | the Program or works based on it. 204 | 205 | 6. Each time you redistribute the Program (or any work based on the 206 | Program), the recipient automatically receives a license from the 207 | original licensor to copy, distribute or modify the Program subject to 208 | these terms and conditions. You may not impose any further 209 | restrictions on the recipients' exercise of the rights granted herein. 210 | You are not responsible for enforcing compliance by third parties to 211 | this License. 212 | 213 | 7. If, as a consequence of a court judgment or allegation of patent 214 | infringement or for any other reason (not limited to patent issues), 215 | conditions are imposed on you (whether by court order, agreement or 216 | otherwise) that contradict the conditions of this License, they do not 217 | excuse you from the conditions of this License. If you cannot 218 | distribute so as to satisfy simultaneously your obligations under this 219 | License and any other pertinent obligations, then as a consequence you 220 | may not distribute the Program at all. For example, if a patent 221 | license would not permit royalty-free redistribution of the Program by 222 | all those who receive copies directly or indirectly through you, then 223 | the only way you could satisfy both it and this License would be to 224 | refrain entirely from distribution of the Program. 225 | 226 | If any portion of this section is held invalid or unenforceable under 227 | any particular circumstance, the balance of the section is intended to 228 | apply and the section as a whole is intended to apply in other 229 | circumstances. 230 | 231 | It is not the purpose of this section to induce you to infringe any 232 | patents or other property right claims or to contest validity of any 233 | such claims; this section has the sole purpose of protecting the 234 | integrity of the free software distribution system, which is 235 | implemented by public license practices. Many people have made 236 | generous contributions to the wide range of software distributed 237 | through that system in reliance on consistent application of that 238 | system; it is up to the author/donor to decide if he or she is willing 239 | to distribute software through any other system and a licensee cannot 240 | impose that choice. 241 | 242 | This section is intended to make thoroughly clear what is believed to 243 | be a consequence of the rest of this License. 244 | 245 | 8. If the distribution and/or use of the Program is restricted in 246 | certain countries either by patents or by copyrighted interfaces, the 247 | original copyright holder who places the Program under this License 248 | may add an explicit geographical distribution limitation excluding 249 | those countries, so that distribution is permitted only in or among 250 | countries not thus excluded. In such case, this License incorporates 251 | the limitation as if written in the body of this License. 252 | 253 | 9. The Free Software Foundation may publish revised and/or new versions 254 | of the General Public License from time to time. Such new versions will 255 | be similar in spirit to the present version, but may differ in detail to 256 | address new problems or concerns. 257 | 258 | Each version is given a distinguishing version number. If the Program 259 | specifies a version number of this License which applies to it and "any 260 | later version", you have the option of following the terms and conditions 261 | either of that version or of any later version published by the Free 262 | Software Foundation. If the Program does not specify a version number of 263 | this License, you may choose any version ever published by the Free Software 264 | Foundation. 265 | 266 | 10. If you wish to incorporate parts of the Program into other free 267 | programs whose distribution conditions are different, write to the author 268 | to ask for permission. For software which is copyrighted by the Free 269 | Software Foundation, write to the Free Software Foundation; we sometimes 270 | make exceptions for this. Our decision will be guided by the two goals 271 | of preserving the free status of all derivatives of our free software and 272 | of promoting the sharing and reuse of software generally. 273 | 274 | NO WARRANTY 275 | 276 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 277 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 278 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 279 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 280 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 281 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 282 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 283 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 284 | REPAIR OR CORRECTION. 285 | 286 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 287 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 288 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 289 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 290 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 291 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 292 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 293 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 294 | POSSIBILITY OF SUCH DAMAGES. 295 | 296 | END OF TERMS AND CONDITIONS 297 | 298 | How to Apply These Terms to Your New Programs 299 | 300 | If you develop a new program, and you want it to be of the greatest 301 | possible use to the public, the best way to achieve this is to make it 302 | free software which everyone can redistribute and change under these terms. 303 | 304 | To do so, attach the following notices to the program. It is safest 305 | to attach them to the start of each source file to most effectively 306 | convey the exclusion of warranty; and each file should have at least 307 | the "copyright" line and a pointer to where the full notice is found. 308 | 309 | 310 | Copyright (C) 311 | 312 | This program is free software; you can redistribute it and/or modify 313 | it under the terms of the GNU General Public License as published by 314 | the Free Software Foundation; either version 2 of the License, or 315 | (at your option) any later version. 316 | 317 | This program is distributed in the hope that it will be useful, 318 | but WITHOUT ANY WARRANTY; without even the implied warranty of 319 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 320 | GNU General Public License for more details. 321 | 322 | You should have received a copy of the GNU General Public License along 323 | with this program; if not, write to the Free Software Foundation, Inc., 324 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 325 | 326 | Also add information on how to contact you by electronic and paper mail. 327 | 328 | If the program is interactive, make it output a short notice like this 329 | when it starts in an interactive mode: 330 | 331 | Gnomovision version 69, Copyright (C) year name of author 332 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 333 | This is free software, and you are welcome to redistribute it 334 | under certain conditions; type `show c' for details. 335 | 336 | The hypothetical commands `show w' and `show c' should show the appropriate 337 | parts of the General Public License. Of course, the commands you use may 338 | be called something other than `show w' and `show c'; they could even be 339 | mouse-clicks or menu items--whatever suits your program. 340 | 341 | You should also get your employer (if you work as a programmer) or your 342 | school, if any, to sign a "copyright disclaimer" for the program, if 343 | necessary. Here is a sample; alter the names: 344 | 345 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 346 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 347 | 348 | , 1 April 1989 349 | Ty Coon, President of Vice 350 | 351 | This General Public License does not permit incorporating your program into 352 | proprietary programs. If your program is a subroutine library, you may 353 | consider it more useful to permit linking proprietary applications with the 354 | library. If this is what you want to do, use the GNU Lesser General 355 | Public License instead of this License. 356 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Freecut: open firmware for Cricut Personal devices. 2 | # 3 | # 4 | # MCU name 5 | MCU = atmega128 6 | 7 | # Output format. (can be srec, ihex) 8 | FORMAT = ihex 9 | 10 | # Target file name (without extension). 11 | TARGET = freecut 12 | 13 | # Speed 14 | FCLK = 16000000UL 15 | 16 | # List C source files here. (C dependencies are automatically generated.) 17 | SRC = main.c usb.c lcd.c keypad.c timer.c stepper.c cli.c flash.c dial.c 18 | 19 | # Assembler sources 20 | ASRC = 21 | 22 | # Optional compiler flags. 23 | CFLAGS = -D$(MCU) $(TEST) $(CE) -Os -DFCLK=$(FCLK) -fpack-struct 24 | CFLAGS += -fshort-enums -Wall -Werror -Wstrict-prototypes 25 | 26 | # Optional assembler flags. 27 | ASFLAGS = -Wa,-ahlms=$(<:.S=.lst),-gstabs 28 | 29 | # Optional linker flags. 30 | LDFLAGS = -Wl,-Map=$(TARGET).map,--cref 31 | 32 | # Additional libraries 33 | # 34 | # Minimalistic printf version 35 | #LDFLAGS += -Wl,-u,vfprintf -lprintf_min 36 | # 37 | # Floating point printf version (requires -lm below) 38 | #LDFLAGS += -Wl,-u,vfprintf -lprintf_flt 39 | # 40 | # -lm = math library 41 | LDFLAGS += -lm 42 | 43 | # --------------------------------------------------------------------------- 44 | 45 | # Define directories, if needed. 46 | 47 | # Define programs and commands. 48 | SHELL = sh 49 | 50 | CC = avr-gcc 51 | 52 | OBJCOPY = avr-objcopy 53 | OBJDUMP = avr-objdump 54 | 55 | # Define all object files. 56 | OBJ = $(ASRC:.S=.o) $(SRC:.c=.o) 57 | 58 | # Define all listing files. 59 | LST = $(ASRC:.S=.lst) $(SRC:.c=.lst) 60 | 61 | # Combine all necessary flags and optional flags. Add target processor to flags. 62 | ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) 63 | ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) 64 | 65 | # Default target. 66 | all: $(TARGET).elf $(TARGET).hex $(TARGET).lss tags 67 | 68 | .PHONY: prog 69 | 70 | prog: all 71 | avrdude -pm128 -cstk500v2 -b115200 -P/dev/ttyUSB0 -u -V -U flash:w:$(TARGET).hex:i 72 | 73 | # Create final output files (.hex) from ELF output file. 74 | %.hex: %.elf 75 | $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ 76 | 77 | # Disassembly listing 78 | %.dis: %.elf 79 | $(OBJDUMP) -d $< > $@ 80 | 81 | # Create extended listing file from ELF output file. 82 | %.lss: %.elf 83 | $(OBJDUMP) -h -S $< > $@ 84 | 85 | # Link: create ELF output file from object files. 86 | .SECONDARY : $(TARGET).elf 87 | .PRECIOUS : $(OBJ) 88 | %.elf: $(OBJ) 89 | $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) 90 | 91 | 92 | # Compile: create object files from C source files. 93 | %.o : %.c 94 | $(CC) -c $(ALL_CFLAGS) $< -o $@ 95 | 96 | 97 | # Compile: create assembler files from C source files. 98 | %.s : %.c 99 | $(CC) -S $(ALL_CFLAGS) $< -o $@ 100 | 101 | 102 | # Assemble: create object files from assembler source files. 103 | %.o : %.S 104 | $(CC) -c $(ALL_ASFLAGS) $< -o $@ 105 | 106 | 107 | # Target: clean project. 108 | 109 | clean : 110 | rm -f *.hex 111 | rm -f *.obj 112 | rm -f *.elf 113 | rm -f *.map 114 | rm -f *.obj 115 | rm -f *.sym 116 | rm -f *.ssm 117 | rm -f *.lnk 118 | rm -f *.lss 119 | rm -f *.lst 120 | rm -f $(OBJ) 121 | rm -f $(LST) 122 | rm -f $(SRC:.c=.s) 123 | rm -f $(SRC:.c=.d) 124 | rm -f logfile 125 | 126 | 127 | # Automatically generate C source code dependencies. 128 | # (Code originally taken from the GNU make user manual and modified (See README.txt Credits).) 129 | # Note that this will work with sh (bash) and sed that is shipped with WinAVR (see the SHELL variable defined above). 130 | # This may not work with other shells or other seds. 131 | %.d: %.c 132 | set -e; $(CC) -MM $(ALL_CFLAGS) $< \ 133 | | sed -e 's,\(.*\)\.o[ :]*,\1.o \1.d : ,g' \ 134 | > $@; [ -s $@ ] || rm -f $@ 135 | 136 | 137 | # Remove the '-' if you want to see the dependency files generated. 138 | -include $(SRC:.c=.d) 139 | 140 | 141 | # Listing of phony targets. 142 | .PHONY : all clean 143 | 144 | tags: *.[hc] 145 | ctags *.[hc] 146 | 147 | 148 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Freecut v0.1 2 | 3 | Free firmware replacement for Cricut(tm) Personal paper cutter. 4 | 5 | ******************************************************************************* 6 | IMPORTANT: REPROGRAMMING THE AVR WILL PERMANENTLY ERASE YOUR ORIGINAL FIRMWARE 7 | 8 | !!! THERE IS NO WAY TO GET THE ORIGINAL FIRMWARE BACK !!! 9 | 10 | ******************************************************************************* 11 | 12 | Original firmware cannot be copied from another machine (it has been 13 | locked and cannot be read from the CPU) 14 | 15 | Original firmware cannot be restored through any PC application used for 16 | normal firmware upgrades. 17 | 18 | This Freecut firmware has only been tested on the machine that I have. It 19 | may not work on your machine. It may cause permanent damage, and it 20 | will certainly void your warranty. 21 | 22 | Freecut cannot read your original cartridges and may never read them in 23 | the future. 24 | 25 | Cricut is a trademark of PROVO CRAFT. 26 | 27 | Freecut is not a PROVO CRAFT product. Freecut was developed completely 28 | independently, without any documentation to PROVO CRAFT products, and without 29 | any original firmware. If you have problems with Freecut, do not consult 30 | PROVO CRAFT. 31 | 32 | 33 | If you still want to proceed: 34 | 35 | Attach an AVR programming cable to cartridge connector on the main board (J5): 36 | 37 | J5 | AVR 38 | ------+----- 39 | 1 | PDO 40 | 3 | SCK 41 | 4 | PDI 42 | 5 | RESET 43 | 6 | GND 44 | 45 | Top view of connector: 46 | 47 | J5 48 | +---- ---+ 49 | | 9 7 5 3 1 | 50 | |10 8 6 4 2 | 51 | +---------------+ 52 | 53 | ===edge of board====== 54 | 55 | And upload the freecut.hex file. 56 | 57 | After reprogramming, the machine should beep, and display "Freecut v0.1" on the LCD display. 58 | Use keypad to load/unload paper (bottom right is unload, one to the left is load) 59 | 60 | Use the USB cable to communicate (keypad is mostly non-functional, as well as the 3 dials on the front). 61 | 62 | USB uses 115200 baud, 8N1. 63 | 64 | Following commands are available: 65 | 66 | version 67 | display version number 68 | 69 | move 70 | lift pen, and move to coordinates. 71 | 72 | draw 73 | drop pen, and move to coordinates. 74 | 75 | curve 76 | drop pen and draw cubic Bezier curve 77 | 78 | speed 79 | lower numbers are faster. 60 is about the fastest practical 80 | speed. 100 is reasonable for most cases. The speed is tied 81 | directly to an AVR timer: speed 100 -> 250 kHz/100 = 2.5 kHz 82 | stepping frequency -> 6.25"/second. If the speed is too high, 83 | the motors will start skipping. 84 | 85 | press 86 | lower numbers are more pressure. 1023 is minimum, 0 is maximum. 87 | 88 | flash 89 | just dumps the internal AT45DB041 flash chip in CAR mode. 90 | 91 | reset 92 | CPU reset 93 | 94 | 95 | Don't send too many commands too quickly. Wait for '>' prompt before sending another line. 96 | 97 | NOTE: This is the first quick & dirty version. User interface may experience 98 | sudden changes (like a more sensible speed/press syntax) 99 | 100 | e-mail: 101 | 102 | 103 | -------------------------------------------------------------------------------- /cli.c: -------------------------------------------------------------------------------- 1 | /* 2 | * cli.c 3 | * 4 | * command line interface 5 | * 6 | * Copyright 2010 7 | * 8 | * This file is part of Freecut. 9 | * 10 | * Freecut is free software: you can redistribute it and/or modify it 11 | * under the terms of the GNU General Public License version 2. 12 | * 13 | * Freecut is distributed in the hope that it will be useful, but WITHOUT 14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 16 | * License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with Freecut. If not, see http://www.gnu.org/licenses/. 20 | * 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "timer.h" 34 | #include "cli.h" 35 | #include "usb.h" 36 | #include "stepper.h" 37 | #include "flash.h" 38 | #include "version.h" 39 | 40 | #define BUFLEN 100 41 | #define MAX_ARGS 10 42 | 43 | static char buf[BUFLEN + 1]; 44 | static char *argv[MAX_ARGS+1]; 45 | static uint8_t buf_len = 0; 46 | static uint8_t argc; 47 | static uint8_t curtok; 48 | static char echo = 0; 49 | static jmp_buf cmd_error; 50 | 51 | enum 52 | { 53 | C_EOL = 0, 54 | C_BAD, 55 | C_NUM, 56 | C_MOVE, 57 | C_DRAW, 58 | C_VERSION, 59 | C_SPEED, 60 | C_PRESS, 61 | C_CURVE, 62 | C_FLASH, 63 | C_RESET, 64 | }; 65 | 66 | static struct token 67 | { 68 | char *lex; 69 | uint8_t class; 70 | long val; 71 | } token; 72 | 73 | static const struct keyword 74 | { 75 | char str[10]; 76 | uint8_t class; 77 | } keyword_list[] PROGMEM = 78 | { 79 | // commands 80 | { "version", C_VERSION }, 81 | { "move", C_MOVE }, 82 | { "draw", C_DRAW }, 83 | { "speed", C_SPEED }, 84 | { "curve", C_CURVE }, 85 | { "press", C_PRESS }, 86 | { "pressure", C_PRESS }, 87 | { "flash", C_FLASH }, 88 | { "reset", C_RESET }, 89 | }; 90 | 91 | #define MAX_KEYWORDS (sizeof(keyword_list) / sizeof(*keyword_list)) 92 | 93 | static const struct keyword *find_keyword( char *str ) 94 | { 95 | unsigned i; 96 | const struct keyword *keyword; 97 | 98 | for( i = 0, keyword = keyword_list; i < MAX_KEYWORDS; i++, keyword++ ) 99 | { 100 | if( !strcmp_P(str, keyword->str) ) 101 | return( keyword ); 102 | } 103 | return( 0 ); 104 | } 105 | 106 | /* 107 | * get next token 108 | */ 109 | static uint8_t get_token( void ) 110 | { 111 | const struct keyword *keyword; 112 | char *lex = argv[curtok]; 113 | uint8_t class; 114 | 115 | token.lex = lex; 116 | if( curtok >= argc ) 117 | { 118 | token.class = C_EOL; 119 | return C_EOL; 120 | } 121 | curtok++; 122 | keyword = find_keyword( lex ); 123 | if( keyword ) 124 | memcpy_P( &class, &keyword->class, sizeof(class) ); 125 | else if( lex[0] == '-' || isdigit(lex[0]) ) 126 | { 127 | token.val = strtol( lex, 0, 10 ); 128 | class = C_NUM; 129 | } 130 | else 131 | class = C_BAD; 132 | token.class = class; 133 | return( class ); 134 | } 135 | 136 | static void expect_token( uint8_t class, const char *what ) 137 | { 138 | if( get_token() == class ) 139 | return; 140 | printf( "expected %s, got '%s'\n", what, token.lex ); 141 | longjmp( cmd_error, 1 ); 142 | } 143 | 144 | static long parse_num( void ) 145 | { 146 | expect_token( C_NUM, "number" ); 147 | return( token.val ); 148 | } 149 | 150 | /* 151 | * split_line: split line into args at spaces. 152 | */ 153 | static char split_line( char *line, char **argv ) 154 | { 155 | uint8_t argc = 0; 156 | char c; 157 | 158 | for( argc = 0; argc < MAX_ARGS; argc++ ) 159 | { 160 | while( *line == ' ' ) 161 | *line++ = 0; 162 | if( !*line ) 163 | break; 164 | argv[argc] = line; 165 | while( (c = *line) != 0 && c != ' ' ) 166 | line++; 167 | } 168 | argv[argc] = ""; 169 | return( argc ); 170 | } 171 | 172 | void version( void ) 173 | { 174 | printf( "Freecut version " VERSION "\n"); 175 | } 176 | 177 | static void parse_speed( void ) 178 | { 179 | stepper_speed( parse_num() ); 180 | } 181 | 182 | static void parse_move( void ) 183 | { 184 | uint16_t x = parse_num( ); 185 | uint16_t y = parse_num( ); 186 | 187 | if( x < 0 ) 188 | x = 0; 189 | stepper_move( x, y ); 190 | } 191 | 192 | static void parse_draw( void ) 193 | { 194 | uint16_t x = parse_num( ); 195 | uint16_t y = parse_num( ); 196 | 197 | stepper_draw( x, y ); 198 | } 199 | 200 | static void bezier_prep( int *k, int *p ) 201 | { 202 | k[0] = -p[0] + 3*p[1] - 3*p[2] + p[3]; 203 | k[1] = 3*p[0] - 6*p[1] + 3*p[2]; 204 | k[2] = -3*p[0] + 3*p[1]; 205 | k[3] = p[0]; 206 | } 207 | 208 | static int bezier_eval( int *p, float t ) 209 | { 210 | float s; 211 | 212 | s = p[0]; s *= t; 213 | s += p[1]; s *= t; 214 | s += p[2]; s *= t; 215 | s += p[3]; 216 | 217 | return (int) (s + 0.5); 218 | } 219 | 220 | static void parse_curve( void ) 221 | { 222 | int i, x, y; 223 | int ox, oy; 224 | int Px[4], Py[4]; // control points, x and y 225 | int Kx[4], Ky[4]; // cubic polynomial coefficients 226 | 227 | for( i = 0; i < 4; i++ ) 228 | { 229 | Px[i] = parse_num( ); 230 | Py[i] = parse_num( ); 231 | } 232 | ox = Px[0]; 233 | oy = Py[0]; 234 | stepper_move( ox, oy ); 235 | bezier_prep( Kx, Px ); 236 | bezier_prep( Ky, Py ); 237 | for( i = 0; i <= 128; i++ ) 238 | { 239 | float t = i / 128.0; 240 | 241 | x = bezier_eval( Kx, t ); 242 | y = bezier_eval( Ky, t ); 243 | if( x != ox || y != oy ) 244 | stepper_draw( x, y ); 245 | ox = x; 246 | oy = y; 247 | } 248 | } 249 | 250 | static void parse_flash( void ) 251 | { 252 | flash_test( ); 253 | } 254 | 255 | static void parse_pressure( void ) 256 | { 257 | stepper_pressure( parse_num() ); 258 | } 259 | 260 | static void parse_reset( void ) 261 | { 262 | cli( ); 263 | wdt_enable( WDTO_15MS ); 264 | while( 1 ); 265 | } 266 | 267 | static void parse( char *buf ) 268 | { 269 | curtok = 0; 270 | 271 | switch( get_token() ) 272 | { 273 | case C_VERSION: version( ); break; 274 | case C_MOVE: parse_move( ); break; 275 | case C_DRAW: parse_draw( ); break; 276 | case C_SPEED: parse_speed( ); break; 277 | case C_PRESS: parse_pressure( ); break; 278 | case C_CURVE: parse_curve( ); break; 279 | case C_FLASH: parse_flash( ); break; 280 | case C_RESET: parse_reset( ); break; 281 | 282 | case C_EOL: 283 | break; 284 | 285 | default: 286 | printf( "unknown command '%s'\n", token.lex ); 287 | return; 288 | } 289 | if( get_token() != C_EOL ) 290 | printf( "unrecognized parameter '%s'\n", token.lex ); 291 | } 292 | 293 | void cli_poll( void ) 294 | { 295 | int c = usb_peek( ); 296 | 297 | if( c < 0 ) 298 | return; 299 | if( c == '\r' || c == '\n' ) 300 | { 301 | printf( "\n" ); 302 | buf[buf_len] = 0; 303 | buf_len = 0; 304 | argc = split_line( buf, argv ); 305 | if( !setjmp(cmd_error) ) 306 | parse( buf ); 307 | printf( "%d>", stepper_queued() ); 308 | } 309 | else if( c == '\b' || c == 0x7f ) 310 | { 311 | if( buf_len > 0 ) 312 | { 313 | buf_len--; 314 | if( echo ) 315 | printf( "\b \b" ); 316 | } 317 | } 318 | else if( c == 5 ) 319 | echo ^= 1; 320 | else if( isprint(c) && buf_len < BUFLEN ) 321 | { 322 | if( echo ) 323 | putchar( c ); 324 | buf[buf_len++] = c; 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /cli.h: -------------------------------------------------------------------------------- 1 | /* 2 | * cli.h 3 | * 4 | * 5 | * Copyright 2010 6 | * 7 | * This file is part of Freecut. 8 | * 9 | * Freecut is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2. 11 | * 12 | * Freecut is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with Freecut. If not, see http://www.gnu.org/licenses/. 19 | * 20 | */ 21 | #ifndef cli_h 22 | #define cli_h 23 | 24 | void cli_poll( void ); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /dial.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dial.c 3 | * 4 | * Driver for 3 analog dials, connected as follows: 5 | * 6 | * dial | AVR 7 | *-------+----------- 8 | * size | PF0 (ADC0) 9 | * speed | PF1 (ADC1) 10 | * press | PF2 (ADC2) 11 | * 12 | * Each input is a simple voltage divider between 0 and 5V, with 13 | * a few discrete settings where the pot clicks. 14 | * 15 | * Copyright 2010 16 | * 17 | * This file is part of Freecut. 18 | * 19 | * Freecut is free software: you can redistribute it and/or modify it 20 | * under the terms of the GNU General Public License version 2. 21 | * 22 | * Freecut is distributed in the hope that it will be useful, but WITHOUT 23 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 24 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 25 | * License for more details. 26 | * 27 | * You should have received a copy of the GNU General Public License 28 | * along with Freecut. If not, see http://www.gnu.org/licenses/. 29 | * 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include "dial.h" 37 | 38 | static uint8_t channel = 0; 39 | 40 | static unsigned char dial_adc[MAX_DIALS]; 41 | static unsigned char dial_steps[MAX_DIALS] = { 10, 5, 5 }; 42 | 43 | static int dial_setting( uint8_t dial ) 44 | { 45 | return( (dial_adc[dial] * (dial_steps[dial]-1) + 125) / 250 ); 46 | } 47 | 48 | int dial_get_speed( void ) 49 | { 50 | return dial_setting( DIAL_SPEED ); 51 | } 52 | 53 | int dial_get_pressure( void ) 54 | { 55 | return dial_setting( DIAL_PRESSURE ); 56 | } 57 | 58 | int dial_get_size( void ) 59 | { 60 | return dial_setting( DIAL_SIZE ); 61 | } 62 | 63 | void dial_poll( void ) 64 | { 65 | ADCSR |= (1 << ADIF); 66 | dial_adc[channel] = ADCH; 67 | if( ++channel == MAX_DIALS ) 68 | channel = 0; 69 | ADMUX = (1 << ADLAR) | (1 << REFS0) | channel; 70 | ADCSRA |= (1 << ADSC); 71 | } 72 | 73 | void dial_init( void ) 74 | { 75 | ADMUX = (1 << ADLAR) | (1 << REFS0) | channel; 76 | ADCSRA = (1 << ADEN) | (1 << ADSC) | 7; 77 | } 78 | -------------------------------------------------------------------------------- /dial.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dial.h 3 | * 4 | * Interface for front panel dials. 5 | * 6 | * Copyright 2010 7 | * 8 | * This file is part of Freecut. 9 | * 10 | * Freecut is free software: you can redistribute it and/or modify it 11 | * under the terms of the GNU General Public License version 2. 12 | * 13 | * Freecut is distributed in the hope that it will be useful, but WITHOUT 14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 16 | * License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with Freecut. If not, see http://www.gnu.org/licenses/. 20 | * 21 | */ 22 | 23 | #ifndef DIALS_H 24 | #define DIALS_H 25 | 26 | enum 27 | { 28 | DIAL_SIZE, 29 | DIAL_SPEED, 30 | DIAL_PRESSURE, 31 | MAX_DIALS 32 | }; 33 | 34 | int dial_get_speed( void ); 35 | int dial_get_pressure( void ); 36 | int dial_get_size( void ); 37 | void dial_poll( void ); 38 | void dial_init( void ); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /flash.c: -------------------------------------------------------------------------------- 1 | /* 2 | * flash.c 3 | * 4 | * Driver for serial dataflash AT45DB041B on main board, attached as follows: 5 | * 6 | * Pin | Func | AVR 7 | *------+-------+--------- 8 | * 1 | SI | PB7 9 | * 2 | SCK | PB1 10 | * 4 | !CS | PB4 11 | * 8 | SO | PB0 12 | * 13 | * only contains a test/dump function for now. 14 | * 15 | * 16 | * Copyright 2010 17 | * 18 | * This file is part of Freecut. 19 | * 20 | * Freecut is free software: you can redistribute it and/or modify it 21 | * under the terms of the GNU General Public License version 2. 22 | * 23 | * Freecut is distributed in the hope that it will be useful, but WITHOUT 24 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 25 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 26 | * License for more details. 27 | * 28 | * You should have received a copy of the GNU General Public License 29 | * along with Freecut. If not, see http://www.gnu.org/licenses/. 30 | * 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include "flash.h" 37 | #include "usb.h" 38 | 39 | #define MISO (1 << 0) 40 | #define SCK (1 << 1) 41 | #define CS (1 << 4) 42 | #define MOSI (1 << 7) 43 | 44 | #define cs_low( ) do { PORTB &= ~CS; } while(0) 45 | #define cs_high( ) do { PORTB |= CS; } while(0) 46 | #define mosi_low( ) do { PORTB &= ~MOSI; } while(0) 47 | #define mosi_high( ) do { PORTB |= MOSI; } while(0) 48 | #define sck_low( ) do { PORTB &= ~SCK; } while(0) 49 | #define sck_high( ) do { PORTB |= SCK; } while(0) 50 | #define get_miso( ) (PINB & 1) 51 | 52 | #define AT_STATUS 0xd7 // status byte 53 | #define AT_CAR 0xe8 // continuous array read 54 | 55 | /* 56 | * write a single byte to flash chip 57 | */ 58 | static void flash_write_byte( uint8_t data ) 59 | { 60 | char i; 61 | 62 | for( i = 0; i < 8; i++ ) 63 | { 64 | if( data & 0x80 ) 65 | mosi_high( ); 66 | else 67 | mosi_low( ); 68 | sck_high( ); 69 | data <<= 1; 70 | sck_low( ); 71 | } 72 | } 73 | 74 | /* 75 | * read a single byte to flash chip 76 | */ 77 | static uint8_t flash_read_byte( void ) 78 | { 79 | uint8_t data = 0; 80 | char i; 81 | 82 | for( i = 0; i < 8; i++ ) 83 | { 84 | sck_high( ); 85 | data = (data << 1) + get_miso( ); 86 | sck_low( ); 87 | } 88 | return data; 89 | } 90 | 91 | /* 92 | * provide 'count' dummy clocks 93 | */ 94 | static void flash_clocks( char count ) 95 | { 96 | while( --count >= 0 ) 97 | { 98 | sck_high( ); 99 | sck_low( ); 100 | } 101 | } 102 | 103 | /* 104 | * read the Flash status byte 105 | */ 106 | static uint8_t flash_read_status( void ) 107 | { 108 | uint8_t status; 109 | 110 | cs_low( ); 111 | flash_write_byte( AT_STATUS ); 112 | status = flash_read_byte( ); 113 | cs_high( ); 114 | return status; 115 | } 116 | 117 | /* 118 | * write a command, consisting of 8 cmd bits, and 24 address bits. 119 | */ 120 | static void flash_write_cmd( uint8_t cmd, uint32_t addr ) 121 | { 122 | cs_low( ); 123 | flash_write_byte( cmd ); 124 | flash_write_byte( addr >> 24 ); 125 | flash_write_byte( addr >> 16 ); 126 | flash_write_byte( addr >> 8 ); 127 | } 128 | 129 | /* 130 | * simple test: dump all contents of built-in cartridge 131 | */ 132 | void flash_test( void ) 133 | { 134 | uint8_t i = 0; 135 | long size = 2048L * 264L; 136 | 137 | flash_write_cmd( AT_CAR, 0 ); 138 | flash_clocks( 32 ); 139 | while( --size >= 0 && usb_peek() != 3 ) 140 | { 141 | printf( "%02x%c", flash_read_byte(), ++i % 16 ? ' ' : '\n' ); 142 | } 143 | cs_high( ); 144 | } 145 | 146 | void flash_init( void ) 147 | { 148 | DDRB |= MOSI | SCK | CS; 149 | flash_read_status( ); 150 | } 151 | -------------------------------------------------------------------------------- /flash.h: -------------------------------------------------------------------------------- 1 | /* 2 | * flash.c 3 | * 4 | * Driver for serial dataflash AT45DB041B on main board, attached as follows: 5 | * 6 | * 7 | * Copyright 2010 8 | * 9 | * This file is part of Freecut. 10 | * 11 | * Freecut is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2. 13 | * 14 | * Freecut is distributed in the hope that it will be useful, but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 17 | * License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with Freecut. If not, see http://www.gnu.org/licenses/. 21 | * 22 | */ 23 | 24 | #ifndef FLASH_H 25 | #define FLASH_H 26 | 27 | void flash_test( void ); 28 | void flash_init( void ); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /keypad.c: -------------------------------------------------------------------------------- 1 | /* 2 | * keypad.c 3 | * 4 | * Keypad is designed as a matrix with 15 rows, and 5 colums. The 15 rows 5 | * are selected using a 16 bit shift register, with CLK/Data inputs. 6 | * 7 | * NOTE: Due to this design, if you press two (or more) keys in the same row 8 | * simultaneously, the the two corresponding outputs of the shift register 9 | * are shorted through the keys, and the CPU gets undefined results. 10 | * 11 | * Pinout of the connector is as follows: 12 | * 13 | * Pin | Name | AVR | Description 14 | *------+-------+------+------------ 15 | * 1 | GND | | 16 | * 2 | Vcc | | 17 | * 3 | Stop | PD0 | Direct connection to stop button 18 | * 4 | O4 | PG4 | Row output 4 (bottom) 19 | * 5 | O3 | PG3 | Row output 3 20 | * 6 | O2 | PG2 | Row output 2 21 | * 7 | O0 | PG0 | Row output 0 (top row) 22 | * 8 | LED | PD5 | LED Enable (0=LEDs on) 23 | * 9 | O1 | PG1 | Row output 1 24 | * 10 | CLK | PD7 | Shift register clock 25 | * 11 | Data | PD6 | Shift register data in 26 | * 12 | Test | | Shift register data out (not used) 27 | * 28 | * Key layout is straightforward: column 0 is left, column 13 is right, 29 | * row 0 is top, row 4 is bottom. The grey arrow keys and CUT key are 30 | * mapped in column 14: 31 | * 32 | * Row | Key 33 | *------+------ 34 | * 0 | Right 35 | * 1 | Left 36 | * 2 | CUT 37 | * 3 | Up 38 | * 4 | Down 39 | * 40 | * The various LEDs are also connected to the shift register outputs, 41 | * and can be turned on with the LED Enable pin (0=On, 1=Off). 42 | * 43 | * LED Layout is as follows: 44 | * 45 | * COL0 COL1 46 | * COL2 COL3 47 | * COL4 COL5 COL10 (LED between CUT and Up arrow) 48 | * COL6 COL7 49 | * COL8 COL9 50 | * 51 | * 52 | * Copyright 2010 53 | * 54 | * This file is part of Freecut. 55 | * 56 | * Freecut is free software: you can redistribute it and/or modify it 57 | * under the terms of the GNU General Public License version 2. 58 | * 59 | * Freecut is distributed in the hope that it will be useful, but WITHOUT 60 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 61 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 62 | * License for more details. 63 | * 64 | * You should have received a copy of the GNU General Public License 65 | * along with Freecut. If not, see http://www.gnu.org/licenses/. 66 | * 67 | */ 68 | 69 | #include 70 | #include 71 | #include 72 | #include 73 | 74 | // pin assignment 75 | #define STOP (1 << 0) // PD0 76 | #define LEDS (1 << 5) // PD5 77 | #define DATA (1 << 6) // PD6 78 | #define CLK (1 << 7) // PD7 79 | #define ROWS (0x1f) // mask for PG4-0 80 | 81 | #define MAX_COLS 16 82 | #define MAX_ROWS 5 83 | 84 | #define leds_on() do { PORTD &= ~LEDS; } while(0) 85 | #define leds_off() do { PORTD |= LEDS; } while(0) 86 | #define clk_h() do { PORTD |= CLK; } while(0) 87 | #define clk_l() do { PORTD &= ~CLK; } while(0) 88 | #define data_h() do { PORTD |= DATA; } while(0) 89 | #define data_l() do { PORTD &= ~DATA; } while(0) 90 | #define get_rows() (~PING & ROWS) 91 | 92 | uint8_t keypad_state[MAX_COLS]; // current state 93 | uint8_t keypad_prev[MAX_COLS]; // previous state 94 | uint16_t leds; 95 | 96 | /* 97 | * keypad_write_cols: write all 16 column bits in 'val' to shift register. 98 | */ 99 | static void keypad_write_cols( short val ) 100 | { 101 | int i; 102 | 103 | for( i = 0; i < MAX_COLS; i++ ) 104 | { 105 | if( val < 0 ) 106 | data_h( ); 107 | else 108 | data_l( ); 109 | clk_h( ); 110 | val <<= 1; 111 | clk_l( ); 112 | } 113 | } 114 | 115 | void keypad_set_leds( uint16_t mask ) 116 | { 117 | leds = mask; 118 | leds_off( ); 119 | keypad_write_cols( ~leds ); 120 | leds_on( ); 121 | } 122 | 123 | /* 124 | * return state of 'STOP' key. 125 | */ 126 | char keypad_stop_pressed( void ) 127 | { 128 | return !(PIND & STOP); 129 | } 130 | 131 | /* 132 | * keypad_scan: perform a single scan of keyboard. Returns keycode of 133 | * key that was pressed (or -1 if nothing). 134 | */ 135 | int keypad_scan( void ) 136 | { 137 | int row, col; 138 | int pressed = -1; 139 | 140 | leds_off( ); // turn off LEDs during scan 141 | keypad_write_cols( ~1 ); // single zero at column 0 142 | data_h( ); // shift in ones 143 | for( col = 0; col < MAX_COLS; col++ ) 144 | { 145 | keypad_state[col] = get_rows( ); 146 | clk_h( ); 147 | clk_l( ); 148 | } 149 | keypad_write_cols( ~leds ); 150 | leds_on( ); 151 | 152 | // keyboard has been scanned, now look for pressed keys 153 | for( col = 0; col < MAX_COLS; col++ ) 154 | { 155 | uint8_t diff = keypad_state[col] ^ keypad_prev[col]; 156 | 157 | if( diff ) 158 | { 159 | for( row = 0; row < MAX_ROWS; row++ ) 160 | { 161 | uint8_t mask = 1 << row; 162 | 163 | if( diff & mask & keypad_state[col] ) 164 | pressed = row * 16 + col; 165 | } 166 | } 167 | keypad_prev[col] = keypad_state[col]; 168 | } 169 | return pressed; 170 | } 171 | 172 | void keypad_init( void ) 173 | { 174 | clk_l( ); 175 | leds_off( ); 176 | DDRD |= (LEDS | DATA | CLK); 177 | PORTD |= STOP; 178 | DDRG &= ~ROWS; // rows are inputs 179 | PORTG |= ROWS; // enable internal pull-ups 180 | } 181 | -------------------------------------------------------------------------------- /keypad.h: -------------------------------------------------------------------------------- 1 | /* keypad.h 2 | * 3 | * Copyright 2010 4 | * 5 | * This file is part of Freecut. 6 | * 7 | * Freecut is free software: you can redistribute it and/or modify it 8 | * under the terms of the GNU General Public License version 2. 9 | * 10 | * Freecut is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 13 | * License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Freecut. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | #ifndef KEYPAD_H 20 | #define KEYPAD_H 21 | 22 | int keypad_scan( void ); 23 | void keypad_init( void ); 24 | void keypad_set_leds( uint16_t mask ); 25 | char keypad_stop_pressed( void ); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /lcd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * lcd.c 3 | * 4 | * Driver for LCD module, based on standard Hitachi H44780, using a 5 | * 10 pin connector for 4-bit only operation. Pinout of the connector 6 | * is as follows: 7 | * 8 | * Pin | Func | AVR 9 | *------+-------+--------- 10 | * 1 | GND | 11 | * 2 | Vcc | 12 | * 3 | RS | PF5 13 | * 4 | R/!W | PF6 14 | * 5 | E | PF7 15 | * 6 | D4 | PE4 16 | * 7 | D5 | PE5 17 | * 8 | D6 | PE6 18 | * 9 | D7 | PE7 19 | * 10 | Light | PF4 (0=On, 1=Off) 20 | * 21 | * The display is 16x1 chars, but is actually wired as a 40x2 line 22 | * display, where the left half is the first line, and the right half 23 | * is the second line. Addresses for the chars are as follows: 24 | * 25 | * 00 01 02 03 04 05 06 07 | 40 41 42 43 44 45 46 47 26 | * 27 | * The lcd_putc()/lcd_pos() functions keep this into account, 28 | * and perform the conversion 29 | * 30 | * 31 | * Copyright 2010 32 | * 33 | * This file is part of Freecut. 34 | * 35 | * Freecut is free software: you can redistribute it and/or modify it 36 | * under the terms of the GNU General Public License version 2. 37 | * 38 | * Freecut is distributed in the hope that it will be useful, but WITHOUT 39 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 40 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 41 | * License for more details. 42 | * 43 | * You should have received a copy of the GNU General Public License 44 | * along with Freecut. If not, see http://www.gnu.org/licenses/. 45 | * 46 | */ 47 | 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include "lcd.h" 53 | #include "timer.h" 54 | 55 | #define BACKLIGHT (1 << 4 ) // 56 | #define RS (1 << 5) // Register Select 57 | #define RW (1 << 6) // Read/Write 58 | #define E (1 << 7) // Enable (Clock) 59 | #define DATA (0xf0) // Data bus mask 60 | 61 | #define rw_h() do { PORTF |= RW; } while(0) 62 | #define rw_l() do { PORTF &= ~RW; } while(0) 63 | 64 | #define e_h() do { PORTF |= E; } while(0) 65 | #define e_l() do { PORTF &= ~E; } while(0) 66 | 67 | #define rs_h() do { PORTF |= RS; } while(0) 68 | #define rs_l() do { PORTF &= ~RS; } while(0) 69 | 70 | uint8_t current_pos = 0; 71 | 72 | FILE lcd = FDEV_SETUP_STREAM( lcd_putchar, 0, _FDEV_SETUP_WRITE ); 73 | 74 | uint8_t lcd_read( void ) 75 | { 76 | uint8_t val; 77 | 78 | PORTE |= DATA; // enable pull ups 79 | DDRE &= ~DATA; // DDRE[4:7] inputs 80 | rw_h( ); // read mode 81 | e_h( ); // two e_h()'s for timing 82 | e_h( ); 83 | val = PINE & 0xf0; // read MS nibble 84 | e_l( ); 85 | e_h( ); 86 | e_h( ); 87 | val |= (PINE >> 4); // read LS nibble 88 | e_l( ); 89 | rw_l( ); // write mode (default) 90 | DDRE |= 0xf0; // PORTE[4:7] outputs 91 | return val; 92 | } 93 | 94 | void lcd_backlight_on( void ) 95 | { 96 | PORTF &= ~BACKLIGHT; 97 | } 98 | 99 | void lcd_backlight_off( void ) 100 | { 101 | PORTF |= BACKLIGHT; 102 | } 103 | 104 | /* 105 | * lcd_wait_ready: wait for busy flag (bit 7) 106 | * to clear. Return -1 on timeout. 107 | */ 108 | int lcd_wait_ready( void ) 109 | { 110 | int i; 111 | 112 | for( i = 0; i < 10000; i++ ) 113 | { 114 | if( !(lcd_read() & 0x80) ) 115 | return 0 ; 116 | } 117 | return -1; 118 | } 119 | 120 | /* 121 | * write top 4 bits of 'val' to LCD module 122 | */ 123 | void lcd_write_nibble( uint8_t val ) 124 | { 125 | PORTE = (PORTE & ~DATA) | (val & DATA); 126 | e_h( ); 127 | e_l( ); 128 | } 129 | 130 | /* 131 | * write 'val' to a Hitachi control register 132 | */ 133 | void lcd_write_control( uint8_t val ) 134 | { 135 | lcd_write_nibble( val ); 136 | lcd_write_nibble( val << 4 ); 137 | lcd_wait_ready( ); 138 | } 139 | 140 | /* 141 | * lcd_pos: set current position 0..15 142 | * 143 | * Convert for split screen (position 8..15 must be mapped to 40..47) 144 | */ 145 | void lcd_pos( uint8_t pos ) 146 | { 147 | if( pos >= 16 ) 148 | pos = 0; 149 | current_pos = pos; 150 | if( pos >= 8 ) 151 | pos += 32; 152 | lcd_write_control( 0x80 + pos ); 153 | } 154 | 155 | /* 156 | * write ASCII character to display 157 | */ 158 | int lcd_putchar( char c, FILE *stream ) 159 | { 160 | if( current_pos >= 16 ) 161 | return 1; 162 | rs_h(); // temporarily select data 163 | lcd_write_nibble( c ); 164 | lcd_write_nibble( c << 4 ); 165 | rs_l( ); // back to control 166 | lcd_wait_ready( ); 167 | // fix for split screen 168 | if( ++current_pos == 8 ) 169 | lcd_pos( current_pos ); 170 | return 1; 171 | } 172 | 173 | /* 174 | * initialize the LCD module. 175 | * 176 | * Between function calls, RS, E, and RW are always kept 0. 177 | */ 178 | void lcd_init( void ) 179 | { 180 | PORTF &= ~(RW | E | RS); 181 | DDRF |= (RW | E | RS | BACKLIGHT); 182 | DDRE |= DATA;; 183 | 184 | // 4-bit init sequence taken from Hitachi datasheet. 185 | 186 | msleep( 15 ); // 15 ms delay to start 187 | lcd_write_nibble( 0x30 ); // 8 bit mode 188 | msleep( 5 ); // > 4.1 ms delay 189 | lcd_write_nibble( 0x30 ); // 8 bit mode 190 | usleep( 100 ); // 100 us delay 191 | lcd_write_nibble( 0x30 ); // 8 bit mode 192 | usleep( 100 ); // 193 | lcd_write_nibble( 0x20 ); // 4 bit mode, as 8 bit command 194 | usleep( 100 ); // 195 | 196 | // now we're in 4-bit mode, and the busy flag should work 197 | 198 | lcd_write_control( 0x28 );// 4 bit, 2 lines, 5x8 dots 199 | lcd_write_control( 0x0c );// turn display on, cursor off 200 | lcd_write_control( 0x01 );// clear display, and go home 201 | current_pos = 0; // remember we're at home position 202 | lcd_backlight_on( ); 203 | } 204 | 205 | /* 206 | * debugging functions, fairly quick so they can be used in ISR. 207 | */ 208 | void lcd_putnibble( uint8_t x ) 209 | { 210 | if( x < 10 ) 211 | lcd_putchar( '0' + x, 0 ); 212 | else 213 | lcd_putchar( 'a' + x - 10, 0 ); 214 | } 215 | 216 | void lcd_puthex( uint8_t x ) 217 | { 218 | lcd_putnibble( x >> 4 ); 219 | lcd_putnibble( x & 0x0f ); 220 | } 221 | -------------------------------------------------------------------------------- /lcd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * lcd.h 3 | * 4 | * support for LCD module 5 | * 6 | * 7 | * Copyright 2010 8 | * 9 | * This file is part of Freecut. 10 | * 11 | * Freecut is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2. 13 | * 14 | * Freecut is distributed in the hope that it will be useful, but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 17 | * License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with Freecut. If not, see http://www.gnu.org/licenses/. 21 | * 22 | */ 23 | 24 | #ifndef LCD_H 25 | #define LCD_H 26 | 27 | #include 28 | #include 29 | 30 | extern FILE lcd; 31 | 32 | void lcd_init( void ); 33 | void lcd_backlight_on( void ); 34 | void lcd_backlight_off( void ); 35 | int lcd_putchar( char c, FILE *stream ); 36 | int lcd_getchar( FILE *stream ); 37 | void lcd_pos( uint8_t pos ); 38 | void lcd_puthex( uint8_t x ); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * main.c 3 | * 4 | * Freecut firmware, main program 5 | * 6 | * 7 | * Copyright 2010 8 | * 9 | * This file is part of Freecut. 10 | * 11 | * Freecut is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2. 13 | * 14 | * Freecut is distributed in the hope that it will be useful, but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 17 | * License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with Freecut. If not, see http://www.gnu.org/licenses/. 21 | * 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "usb.h" 30 | #include "keypad.h" 31 | #include "lcd.h" 32 | #include "timer.h" 33 | #include "stepper.h" 34 | #include "cli.h" 35 | #include "flash.h" 36 | #include "version.h" 37 | #include "dial.h" 38 | 39 | static FILE usb = FDEV_SETUP_STREAM( usb_putchar, usb_getchar, _FDEV_SETUP_RW ); 40 | 41 | #define LOAD_PAPER 0x4c 42 | #define UNLOAD_PAPER 0x4d 43 | 44 | void poll_keypad( void ) 45 | { 46 | int key = keypad_scan( ); 47 | 48 | switch( key ) 49 | { 50 | case LOAD_PAPER: 51 | stepper_load_paper(); 52 | break; 53 | 54 | case UNLOAD_PAPER: 55 | stepper_unload_paper(); 56 | break; 57 | 58 | default: 59 | if( key >= 0 ) 60 | printf( "# unknown key %02x\n", key ); 61 | } 62 | } 63 | 64 | int main( void ) 65 | { 66 | wdt_enable( WDTO_30MS ); 67 | usb_init( ); 68 | timer_init( ); 69 | stepper_init( ); 70 | sei( ); 71 | lcd_init( ); 72 | keypad_init( ); 73 | flash_init( ); 74 | dial_init( ); 75 | 76 | wdt_reset( ); 77 | 78 | // short beep to show we're awake 79 | beeper_on( 1760 ); 80 | msleep( 10 ); 81 | beeper_off( ); 82 | 83 | // connect stdout to USB port 84 | stdout = &usb; 85 | printf( "Freecut v" VERSION "\n\n" ); 86 | fprintf( &lcd, "Freecut v" VERSION ); 87 | while( 1 ) 88 | { 89 | cli_poll( ); 90 | wdt_reset( ); 91 | if( flag_25Hz ) 92 | { 93 | flag_25Hz = 0; 94 | dial_poll( ); 95 | poll_keypad( ); 96 | } 97 | if( flag_Hz ) 98 | { 99 | flag_Hz = 0; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /stepper.c: -------------------------------------------------------------------------------- 1 | /* 2 | * stepper.c 3 | * 4 | * Driver for stepper motors. Each motor is a 6-wire unipolar model. Each of 5 | * the 4 coils (per motor) can be driven with a full current (through the big 6 | * transistor) or a reduced current (through a smaller transistor + 47 Ohm 7 | * resistor). The reduced current I call 'half current', but it may be less. 8 | * 9 | * The Y motor (pen movement) is controlled through PORTC, and the X motor 10 | * (mat roller) is controlled through PORTA. Connections are identical. 11 | * 12 | * In addition, the Z coordinate is controlled by two pins: PE2 is used 13 | * for up/down toggle, and PB6 selects the pressure with a PWM signal. 14 | * 15 | * A small pushbutton is attached to PD1, which is active low when 16 | * pushed. This button detects when the gray cover on the pen holder is 17 | * moved all the way to the 'home' position. 18 | * 19 | * Step resolution is about 400 steps/inch. For a 6x12 inch mat, that means 20 | * there's about 2400x4800 steps of usable space. Coordinate origin is the 21 | * blade starting point on the mat. A small amount of negative X is allowed 22 | * to roll the mat out of the machine. 23 | * 24 | * 25 | * Copyright 2010 26 | * 27 | * This file is part of Freecut. 28 | * 29 | * Freecut is free software: you can redistribute it and/or modify it 30 | * under the terms of the GNU General Public License version 2. 31 | * 32 | * Freecut is distributed in the hope that it will be useful, but WITHOUT 33 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 34 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 35 | * License for more details. 36 | * 37 | * You should have received a copy of the GNU General Public License 38 | * along with Freecut. If not, see http://www.gnu.org/licenses/. 39 | * 40 | */ 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include "lcd.h" 48 | #include "stepper.h" 49 | #include "keypad.h" 50 | #include "timer.h" 51 | 52 | #define MAT_EDGE 250 // distance to roll to load mat 53 | #define MAX_Y 2400 54 | #define MAX_X 4800 55 | 56 | #define DEBUG (1 << 5) // use PB5 for debugging 57 | #define debug_on() do { PORTB |= DEBUG; } while(0) 58 | #define debug_off() do { PORTB &= ~DEBUG; } while(0) 59 | 60 | /* 61 | * Pinout for the PORTA as well as PORTC port 62 | */ 63 | #define H0 0x01 // half current, coil 0 64 | #define F0 0x02 // full current, coil 0 65 | #define H1 0x04 // half current, coil 1 66 | #define F1 0x08 // full current, coil 1 67 | #define H2 0x10 // half current, coil 2 68 | #define F2 0x20 // full current, coil 2 69 | #define H3 0x40 // half current, coil 3 70 | #define F3 0x80 // full current, coil 3 71 | 72 | #define HOME (1 << 1 ) // PD1, attached to 'home' push button 73 | #define PEN (1 << 2) // PE2, attached to pen up/down output 74 | 75 | #define at_home( ) (!(PIND & HOME)) 76 | 77 | /* 78 | * motor phases: There are 16 different stepper motor phases, using 79 | * various combinations of full/half power to create the smallest 80 | * possible steps: 81 | * 82 | * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 83 | * ___________ . . . . . . . . . . .________ 84 | * . . \___ . . . . . . . . ___/ . . 85 | * 0 . . . \___________________________________/ . . . 86 | * . . . . . . . . . . . . . . . . 87 | * . . . . . . . . . . . . . . . . 88 | * . .___________________ . . . . . . . . . 89 | * .___/ . . . \___ . . . . . . . . 90 | * 1 __/ . . . . . \________________________________ 91 | * . . . . . . . . . . . . . . . . 92 | * . . . . . ___________________ . . . . . 93 | * . . . . ___/ . . . \___. . . . . 94 | * 2 __________________/ . . . . . \________________ 95 | * . . . . . . . . . . . . . . . . 96 | * . . . . . . . . . ___________________ . 97 | * . . . . . . . . .___/ . . . \___ 98 | * 3 __________________________________/ . . . . . \ 99 | * 100 | * 101 | */ 102 | static uint8_t phase[] = 103 | { 104 | F0, F0|H1, F0|F1, H0|F1, 105 | F1, F1|H2, F1|F2, H1|F2, 106 | F2, F2|H3, F2|F3, H2|F3, 107 | F3, F3|H0, F3|F0, H3|F0, 108 | }; 109 | 110 | /* 111 | * current position. 112 | * 113 | * Initialize at left (away from home switch), and with the mat touching 114 | * the rollers, such that loading the mat is a simple movement to (0,0) 115 | */ 116 | 117 | static int x = -MAT_EDGE, y = 2400; 118 | 119 | /* 120 | * current pressure 121 | */ 122 | 123 | static int pressure = 1023; 124 | 125 | /* 126 | * experimental soft pen drop parameters 127 | */ 128 | int pen_time[4] = { 10, 12, 40 }; 129 | static int pen_seq; 130 | 131 | static struct bresenham 132 | { 133 | int step; // current step 134 | int steps; // number of steps in main direction 135 | int delta; // number of steps in other direction 136 | int error; // residual error 137 | int dx; // x step direction 138 | int dy; // y step direction 139 | char steep; // y > x 140 | } b; 141 | 142 | static int delay; // delay between steps (if not 0) 143 | 144 | static enum state 145 | { 146 | HOME1, // homing until switch is pushed 147 | HOME2, // reversing until switch is released 148 | READY, // motor off, pen up 149 | LINE // draw straight line 150 | } state; 151 | 152 | /* 153 | * command queue. The stepper controller takes commands from the queue 154 | * using step timer interrupt. Main program can put new commands in. 155 | * 156 | * The idea behind this queue is to keep the movement engine as busy as 157 | * possible, by smoothly joining the end of one stroke with the beginning of 158 | * the next one, so ideally the whole path can be traced in one continuous 159 | * motion. 160 | */ 161 | 162 | #define CMD_QUEUE_SIZE 8 // must be power of two 163 | 164 | enum type 165 | { 166 | MOVE, // move with pen up 167 | DRAW, // move with pen down 168 | SPEED, // set speed 169 | PRESSURE, // set pressure 170 | }; 171 | 172 | struct cmd 173 | { 174 | enum type type; // command type, 175 | int x, y; // target coordinates 176 | } cmd_queue[CMD_QUEUE_SIZE]; 177 | 178 | static volatile uint8_t cmd_head, cmd_tail; 179 | 180 | int stepper_queued( void ) 181 | { 182 | return (char) (cmd_head - cmd_tail); 183 | } 184 | 185 | void stepper_off( void ) 186 | { 187 | PORTA = 0; 188 | PORTC = 0; 189 | } 190 | 191 | /* 192 | * allocate a new command, fill in the type, but don't put it in the queue yet. 193 | */ 194 | static struct cmd *alloc_cmd( uint8_t type ) 195 | { 196 | struct cmd *cmd; 197 | 198 | while( (uint8_t) (cmd_head - cmd_tail) >= CMD_QUEUE_SIZE ) 199 | wdt_reset( ); 200 | cmd = &cmd_queue[cmd_head % CMD_QUEUE_SIZE]; 201 | cmd->type = type; 202 | return cmd; 203 | } 204 | 205 | /* 206 | * get next command from the queue (called in ISR) 207 | */ 208 | static struct cmd *get_cmd( void ) 209 | { 210 | if( cmd_head == cmd_tail ) 211 | return 0; 212 | else 213 | return &cmd_queue[cmd_tail++ % CMD_QUEUE_SIZE]; 214 | } 215 | 216 | /* 217 | * move to coordinate (x, y) with pen lifted. We allow moving 218 | * beyond the mat so that it will roll out. 219 | */ 220 | void stepper_move( int x, int y ) 221 | { 222 | struct cmd *cmd = alloc_cmd( MOVE ); 223 | 224 | if( x < -MAT_EDGE || x > MAX_X || y < 0 || y > MAX_Y ) 225 | return; 226 | cmd->x = x; 227 | cmd->y = y; 228 | cmd_head++; 229 | } 230 | 231 | /* 232 | * draw to coordinate (x, y) with pen dropped. 233 | */ 234 | void stepper_draw( int x, int y ) 235 | { 236 | struct cmd *cmd = alloc_cmd( DRAW ); 237 | 238 | if( x < 0 || x > MAX_X || y < 0 || y > MAX_Y ) 239 | return; 240 | cmd->x = x; 241 | cmd->y = y; 242 | cmd_head++; 243 | } 244 | 245 | void stepper_speed( int speed ) 246 | { 247 | struct cmd *cmd = alloc_cmd( SPEED ); 248 | 249 | cmd->x = speed; 250 | cmd_head++; 251 | } 252 | 253 | /* 254 | * loading paper. If x < 0, the mat needs to be pulled under the rollers first. 255 | * This is a heavy operation, so it's done at reduced speed. In all other 256 | * cases, just move the pen to the origin. 257 | */ 258 | void stepper_load_paper( void ) 259 | { 260 | if( x < 0 ) 261 | { 262 | stepper_speed( 250 ); 263 | stepper_move( 0, y ); // don't move Y direction yet (it may be slow) 264 | } 265 | stepper_speed( 100 ); 266 | stepper_move( 0, 0 ); 267 | } 268 | 269 | /* 270 | * unloading the paper is simple, just go to a position outside the drawing 271 | * area, and the mat will roll out. 272 | */ 273 | void stepper_unload_paper( void ) 274 | { 275 | stepper_speed( 100 ); 276 | stepper_move( -MAT_EDGE, 0 ); 277 | } 278 | 279 | /* 280 | * set the pressure on the pen. 281 | */ 282 | void stepper_pressure( int pressure ) 283 | { 284 | struct cmd *cmd = alloc_cmd( PRESSURE ); 285 | 286 | cmd->x = pressure; 287 | cmd_head++; 288 | } 289 | 290 | /* 291 | * get current position. Only an indication for debugging purposes. 292 | * During movement, this position changes asynchronously. 293 | */ 294 | void stepper_get_pos( int *px, int *py ) 295 | { 296 | *px = x; 297 | *py = y; 298 | } 299 | 300 | /* 301 | * The original firmware also removes the PWM signal, but it seems 302 | * to work ok when you leave it on. 303 | */ 304 | static void pen_up( void ) 305 | { 306 | if( PORTE & PEN ) 307 | delay = 50; 308 | PORTE &= ~PEN; 309 | pen_seq = -1; 310 | } 311 | 312 | /* 313 | * move pen down 314 | */ 315 | static void pen_down( void ) 316 | { 317 | if( PORTE & PEN ) // already down, ignore 318 | return; 319 | /* 320 | * soft pen drop with lowest pressure 321 | */ 322 | timer_set_pen_pressure( 1023 ); 323 | PORTE |= PEN; 324 | pen_seq = 0; 325 | delay = pen_time[2]; 326 | } 327 | 328 | /* 329 | * initialize Bresenham line drawing algorithm. Draw from (x, y) 330 | * to (x1, y1). 331 | */ 332 | static void bresenham_init( int x1, int y1 ) 333 | { 334 | int dx, dy; 335 | 336 | if( x1 > x ) 337 | { 338 | b.dx = 1; 339 | dx = x1 - x; 340 | } 341 | else 342 | { 343 | b.dx = -1; 344 | dx = x - x1; 345 | } 346 | if( y1 > y ) 347 | { 348 | b.dy = 1; 349 | dy = y1 - y; 350 | } 351 | else 352 | { 353 | b.dy = -1; 354 | dy = y - y1; 355 | } 356 | if( dx > dy ) 357 | { 358 | b.steep = 0; 359 | b.steps = dx; 360 | b.delta = dy; 361 | } 362 | else 363 | { 364 | b.steep = 1; 365 | b.steps = dy; 366 | b.delta = dx; 367 | } 368 | b.step = 0; 369 | b.error = b.steps / 2; 370 | } 371 | 372 | /* 373 | * perform single step in Bresenham line drawing algorithm. 374 | */ 375 | static void bresenham_step( void ) 376 | { 377 | if( b.step >= b.steps ) 378 | { 379 | state = READY; 380 | return; 381 | } 382 | b.step++; 383 | if( (b.error -= b.delta) < 0 ) 384 | { 385 | b.error += b.steps; 386 | x += b.dx; 387 | y += b.dy; 388 | } 389 | else if( b.steep ) 390 | y += b.dy; 391 | else 392 | x += b.dx; 393 | } 394 | 395 | /* 396 | * get next command from command queue. 397 | */ 398 | enum state do_next_command( void ) 399 | { 400 | struct cmd *cmd = get_cmd( ); 401 | 402 | if( !cmd ) 403 | { 404 | pen_up( ); 405 | return READY; 406 | } 407 | switch( cmd->type ) 408 | { 409 | case MOVE: 410 | case DRAW: 411 | // FIXME: avoid null-movements earlier 412 | if( x == cmd->x && y == cmd->y ) 413 | return READY; 414 | if( cmd->type == MOVE ) 415 | pen_up(); 416 | else 417 | pen_down( ); 418 | bresenham_init( cmd->x, cmd->y ); 419 | return LINE; 420 | 421 | case PRESSURE: 422 | pressure = cmd->x; 423 | timer_set_pen_pressure( pressure ); 424 | break; 425 | 426 | case SPEED: 427 | timer_set_stepper_speed( cmd->x ); 428 | break; 429 | } 430 | return READY; 431 | } 432 | 433 | /* 434 | * This function is called by a timer interrupt. It does one motor step 435 | * (if active). 436 | */ 437 | void stepper_tick( void ) 438 | { 439 | /* 440 | * experimental soft pen drop. 441 | * A. At time=0, pen is dropped with minimal pressure 442 | * B. At time=pen_time[0] pen is lifted again 443 | * C. At time=pen_time[1] pen is dropped with set pressure 444 | * 445 | * The B-C interval should be short enough such that the pen 446 | * isn't actually going back up, but just loses most of its 447 | * downward speed. This fixed the 'heavy dot' problem at the 448 | * the start of a stroke. Unfortunately, there's still a 449 | * 'heavy dot' when the pen is lifted. 450 | * 451 | * Timing is still tied to stepper tick units, which should be 452 | * fixed. 453 | */ 454 | if( pen_seq >= 0 ) 455 | { 456 | pen_seq++; 457 | if( pen_seq >= pen_time[1] ) 458 | { 459 | PORTE |= PEN; 460 | timer_set_pen_pressure( pressure ); 461 | pen_seq = -1; 462 | } 463 | else if( pen_seq >= pen_time[0] ) 464 | PORTE &= ~PEN; 465 | } 466 | 467 | if( delay && --delay ) 468 | return; 469 | 470 | // abort cutting if 'STOP' is pressed. 471 | if( keypad_stop_pressed() ) 472 | { 473 | state = READY; 474 | x = 0; 475 | cmd_tail = cmd_head; 476 | pen_up(); 477 | stepper_off( ); 478 | } 479 | again: 480 | switch( state ) 481 | { 482 | case HOME1: 483 | if( !at_home() && y > 0 ) 484 | y--; 485 | else 486 | state = HOME2; 487 | break; 488 | 489 | case HOME2: 490 | if( at_home() ) 491 | y++; 492 | else 493 | { 494 | y = 0; 495 | state = READY; 496 | } 497 | break; 498 | 499 | case READY: 500 | state = do_next_command( ); 501 | if( state != READY ) 502 | goto again; 503 | break; 504 | 505 | case LINE: 506 | bresenham_step( ); 507 | break; 508 | } 509 | if( state == READY ) 510 | { 511 | /* 512 | * the motors get quite hot when powered on, so we turn them off 513 | * when idling. Ideally, you'd want to leave them on, so the user 514 | * can't move the pen/mat around. Maybe leave them at half-power ? 515 | */ 516 | stepper_off( ); 517 | } 518 | else 519 | { 520 | PORTA = phase[x & 0x0f]; // low 4 bits determine phase 521 | PORTC = phase[y & 0x0f]; 522 | } 523 | } 524 | 525 | void stepper_init( void ) 526 | { 527 | stepper_off( ); 528 | pen_up( ); 529 | //DDRB |= DEBUG; 530 | DDRA = 0xff; 531 | DDRC = 0xff; 532 | DDRE |= PEN; 533 | PORTD |= HOME; // enable pull-up 534 | } 535 | -------------------------------------------------------------------------------- /stepper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * stepper.h 3 | * 4 | * stepper X/Y/Z movement 5 | * 6 | * 7 | * Copyright 2010 8 | * 9 | * This file is part of Freecut. 10 | * 11 | * Freecut is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2. 13 | * 14 | * Freecut is distributed in the hope that it will be useful, but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 17 | * License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with Freecut. If not, see http://www.gnu.org/licenses/. 21 | * 22 | */ 23 | 24 | #ifndef STEPPER_H 25 | #define STEPPER_H 26 | 27 | void stepper_init( void ); 28 | void stepper_tick( void ); 29 | void stepper_move( int x, int y ); 30 | void stepper_draw( int x, int y ); 31 | void stepper_speed( int delay ); 32 | void stepper_pressure( int pressure ); 33 | void stepper_get_pos( int *x, int *y ); 34 | int stepper_queued( void ); 35 | void stepper_unload_paper( void ); 36 | void stepper_load_paper( void ); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /timer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * timer.c 3 | * 4 | * Timer 0 is used as overall (slow) event timer, as well sleep delay timer. 5 | * Timer 1 is used as solenoid PWM, through OC1B output 6 | * Timer 2 is used for stepper timing 7 | * Timer 3 is used to generate tones on the speaker through OC3A output, 8 | * period is adjusted for tone. 9 | * 10 | * 11 | * Copyright 2010 12 | * 13 | * This file is part of Freecut. 14 | * 15 | * Freecut is free software: you can redistribute it and/or modify it 16 | * under the terms of the GNU General Public License version 2. 17 | * 18 | * Freecut is distributed in the hope that it will be useful, but WITHOUT 19 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 20 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 21 | * License for more details. 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with Freecut. If not, see http://www.gnu.org/licenses/. 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "timer.h" 34 | #include "stepper.h" 35 | 36 | static uint8_t count_Hz = 250; 37 | static uint8_t count_25Hz = 10; 38 | volatile uint8_t flag_Hz; 39 | volatile uint8_t flag_25Hz; 40 | 41 | /* 42 | * called @250 Hz, divide further in software for slow events 43 | */ 44 | SIGNAL( SIG_OUTPUT_COMPARE0 ) 45 | { 46 | if( --count_25Hz == 0 ) 47 | { 48 | count_25Hz = 10; 49 | flag_25Hz = 1; 50 | } 51 | if( --count_Hz == 0 ) 52 | { 53 | count_Hz = 250; 54 | flag_Hz = 1; 55 | } 56 | } 57 | 58 | /* 59 | * Timer 2 compare match, update stepper motors. 60 | */ 61 | SIGNAL( SIG_OUTPUT_COMPARE2 ) 62 | { 63 | stepper_tick( ); 64 | } 65 | 66 | /* 67 | * Turn on beeper. Hz specifies frequency of the tone. 68 | */ 69 | void beeper_on( int Hz ) 70 | { 71 | DDRE |= (1 << 3); 72 | OCR3A = (8000000L + Hz/2) / Hz - 1; 73 | } 74 | 75 | void beeper_off( void ) 76 | { 77 | DDRE &= ~(1 << 3); 78 | } 79 | 80 | /* 81 | * usleep: sleep (approximate/minimum) number of microseconds. We use timer0 82 | * which runs at 62.50 kHz, or at 16 usec/tick. Maximum delay is about 2 83 | * milliseconds . For longer delays, use msleep(). 84 | * 85 | */ 86 | void usleep( int usecs ) 87 | { 88 | signed char end = TCNT0 + usecs / 16; 89 | 90 | while( (signed char) (TCNT0 - end) < 0 ) 91 | continue; 92 | } 93 | 94 | void msleep( unsigned msecs ) 95 | { 96 | while( msecs-- != 0 ) 97 | usleep( 1000 ); 98 | } 99 | 100 | void timer_set_stepper_speed( int delay ) 101 | { 102 | uint8_t prescaler = 4; // default 1:64 prescaler 103 | 104 | if( delay < 30 ) 105 | delay = 30; 106 | else if( delay > 1000 ) 107 | delay = 1000; 108 | TCCR2 &= ~7; // stop timer, and clear prescaler bit 109 | if( delay > 256 ) 110 | { 111 | delay /= 4; 112 | prescaler = 5; 113 | } 114 | OCR2 = delay - 1; 115 | TCCR2 |= prescaler; 116 | } 117 | 118 | void timer_set_pen_pressure( int pressure ) 119 | { 120 | if( pressure > 1023 ) 121 | pressure = 1023; 122 | OCR1B = pressure; 123 | } 124 | 125 | /* 126 | * Init timers 127 | */ 128 | void timer_init( void ) 129 | { 130 | // set timer 0 for 250 Hz period 131 | TCCR0 = (1 << WGM01) | 6; // prescaler 1:256 -> 62.50 kHz 132 | OCR0 = 249; // 125 kHz / 250 = 250 Hz 133 | TIMSK = (1 << OCIE0); // enable OVF interrupt 134 | 135 | // set timer 1, WGM mode 7, fast PWM 10 bit 136 | DDRB |= (1 << 6); // PB6 is PWM output 137 | TCCR1A = (1 << WGM11) | (1 << WGM10) | (1 << COM1B1); 138 | TCCR1B = (1 << WGM12) | 1; 139 | OCR1B = 1023; // lowest pressure 140 | 141 | // set timer 2, variable period for stepper 142 | TCCR2 = (1 << WGM21) | 4; // prescaler 1/256 -> 250 kHz 143 | OCR2 = 99; // default speed 2.5k steps 144 | TIMSK |= (1 << OCIE2); // 145 | 146 | // Timer 3, WGM mode 15 (1111), Fast PWM using OCR3A 147 | TCCR3A = (1 << COM3A0) | (1 << WGM31) | (1 << WGM30); 148 | TCCR3B = (1 << WGM33) | (1 << WGM32) | 1; 149 | } 150 | -------------------------------------------------------------------------------- /timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * timer.h 3 | * 4 | * 5 | * Copyright 2010 6 | * 7 | * This file is part of Freecut. 8 | * 9 | * Freecut is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2. 11 | * 12 | * Freecut is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with Freecut. If not, see http://www.gnu.org/licenses/. 19 | * 20 | */ 21 | #ifndef TIMER_H 22 | #define TIMER_H 23 | 24 | void timer_init( void ); 25 | void usleep( int usecs ); 26 | void msleep( unsigned msecs ); 27 | void beeper_on( int Hz ); 28 | void beeper_off( void ); 29 | void timer_set_stepper_speed( int delay ); 30 | void timer_set_pen_pressure( int pressure ); 31 | 32 | extern volatile uint8_t flag_Hz; 33 | extern volatile uint8_t flag_25Hz; 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /usb.c: -------------------------------------------------------------------------------- 1 | /* 2 | * usb.c 3 | * 4 | * The USB port is a UART, connected to a FTDI chip. 5 | * 6 | * 7 | * Copyright 2010 8 | * 9 | * This file is part of Freecut. 10 | * 11 | * Freecut is free software: you can redistribute it and/or modify it 12 | * under the terms of the GNU General Public License version 2. 13 | * 14 | * Freecut is distributed in the hope that it will be useful, but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 17 | * License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with Freecut. If not, see http://www.gnu.org/licenses/. 21 | * 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "usb.h" 30 | 31 | // these must be powers of two 32 | #define USB_INBUF_LEN 128 33 | #define USB_OUTBUF_LEN 32 34 | 35 | static uint8_t usb_tx_buf[USB_OUTBUF_LEN]; 36 | static uint8_t usb_rx_buf[USB_INBUF_LEN]; 37 | 38 | volatile static uint8_t usb_tx_head = 0; 39 | volatile static uint8_t usb_tx_tail = 0; 40 | volatile static uint8_t usb_rx_head = 0; 41 | volatile static uint8_t usb_rx_tail = 0; 42 | 43 | /* 44 | * transmit interrupt handler 45 | */ 46 | SIGNAL( SIG_UART1_DATA ) 47 | { 48 | if( usb_tx_tail == usb_tx_head ) 49 | UCSR1B &= ~(1 << UDRIE1); 50 | else 51 | UDR1 = usb_tx_buf[usb_tx_tail++ % USB_OUTBUF_LEN]; 52 | } 53 | 54 | /* 55 | * receive interrupt handler 56 | */ 57 | SIGNAL( SIG_UART1_RECV ) 58 | { 59 | char c = UDR1; 60 | 61 | if( (uint8_t) (usb_rx_head - usb_rx_tail) >= USB_INBUF_LEN ) 62 | return; 63 | usb_rx_buf[usb_rx_head++ % USB_INBUF_LEN] = c; 64 | } 65 | 66 | /* 67 | * set the baud rate. Assumes 2X flag is set 68 | */ 69 | void usb_set_baud( long baud ) 70 | { 71 | int div = (FCLK + baud*4) / (baud * 8) - 1; 72 | 73 | UBRR1H = div >> 8; 74 | UBRR1L = div; 75 | } 76 | 77 | /* 78 | * write a single character to output queue, and enable Tx interrupts. 79 | */ 80 | int usb_putchar( char c, FILE *stream ) 81 | { 82 | if( c == '\n' ) 83 | usb_putchar( '\r', stream ); 84 | while( (uint8_t) (usb_tx_head - usb_tx_tail) == USB_OUTBUF_LEN ) 85 | wdt_reset( ); 86 | usb_tx_buf[usb_tx_head++ % USB_OUTBUF_LEN] = c; 87 | UCSR1B |= (1 << UDRIE1 ); 88 | return 0; 89 | } 90 | 91 | /* 92 | * look to see if Rx character is available, return -1 if not. 93 | */ 94 | int usb_peek( void ) 95 | { 96 | if( usb_rx_head == usb_rx_tail ) 97 | return -1; 98 | return usb_rx_buf[usb_rx_tail++ % USB_INBUF_LEN]; 99 | } 100 | 101 | /* 102 | * wait for character to be available. 103 | */ 104 | int usb_getchar( FILE *stream ) 105 | { 106 | int c; 107 | 108 | while( (c = usb_peek()) < 0 ) 109 | wdt_reset( ); 110 | return c; 111 | } 112 | 113 | /* 114 | * initialize USB UART. Assume fixed baudrate of 115200, and default 8N1. 115 | */ 116 | void usb_init( void ) 117 | { 118 | UCSR1A = (1 << U2X1); 119 | UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 << UDRIE1) | (1 << TXEN1); 120 | usb_set_baud( 115200L ); 121 | } 122 | -------------------------------------------------------------------------------- /usb.h: -------------------------------------------------------------------------------- 1 | /* 2 | * usb.h 3 | * 4 | * 5 | * Copyright 2010 6 | * 7 | * This file is part of Freecut. 8 | * 9 | * Freecut is free software: you can redistribute it and/or modify it 10 | * under the terms of the GNU General Public License version 2. 11 | * 12 | * Freecut is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with Freecut. If not, see http://www.gnu.org/licenses/. 19 | * 20 | */ 21 | #ifndef USB_H 22 | #define USB_H 23 | 24 | #include 25 | 26 | void usb_init( void ); 27 | void usb_set_baud( long baud ); 28 | int usb_putchar( char c, FILE *stream ); 29 | int usb_getchar( FILE *stream ); 30 | int usb_peek( void ); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /version.h: -------------------------------------------------------------------------------- 1 | #define VERSION "0.1" 2 | 3 | --------------------------------------------------------------------------------