+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F10x_CONF_H
+#define __STM32F10x_CONF_H
+
+/* Includes ------------------------------------------------------------------*/
+/* Uncomment the line below to enable peripheral header file inclusion */
+/* #include "stm32f10x_adc.h" */
+/* #include "stm32f10x_bkp.h" */
+/* #include "stm32f10x_can.h" */
+/* #include "stm32f10x_cec.h" */
+/* #include "stm32f10x_crc.h" */
+/* #include "stm32f10x_dac.h" */
+/* #include "stm32f10x_dbgmcu.h" */
+/* #include "stm32f10x_dma.h" */
+/* #include "stm32f10x_exti.h" */
+/* #include "stm32f10x_flash.h" */
+/* #include "stm32f10x_fsmc.h" */
+/* #include "stm32f10x_gpio.h" */
+/* #include "stm32f10x_i2c.h" */
+/* #include "stm32f10x_iwdg.h" */
+/* #include "stm32f10x_pwr.h" */
+/* #include "stm32f10x_rcc.h" */
+/* #include "stm32f10x_rtc.h" */
+/* #include "stm32f10x_sdio.h" */
+/* #include "stm32f10x_spi.h" */
+/* #include "stm32f10x_tim.h" */
+/* #include "stm32f10x_usart.h" */
+/* #include "stm32f10x_wwdg.h" */
+/* #include "misc.h" */ /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
+
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+/* Uncomment the line below to expanse the "assert_param" macro in the
+ Standard Peripheral Library drivers code */
+/* #define USE_FULL_ASSERT 1 */
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef USE_FULL_ASSERT
+
+/**
+ * @brief The assert_param macro is used for function's parameters check.
+ * @param expr: If expr is false, it calls assert_failed function
+ * which reports the name of the source file and the source
+ * line number of the call that failed.
+ * If expr is true, it returns no value.
+ * @retval None
+ */
+ #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+ void assert_failed(uint8_t* file, uint32_t line);
+#else
+ #define assert_param(expr) ((void)0)
+#endif /* USE_FULL_ASSERT */
+
+#endif /* __STM32F10x_CONF_H */
+
+/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/
diff --git a/cmsis_boot/system_stm32f10x.c b/cmsis_boot/system_stm32f10x.c
new file mode 100644
index 00000000..71efc858
--- /dev/null
+++ b/cmsis_boot/system_stm32f10x.c
@@ -0,0 +1,1094 @@
+/**
+ ******************************************************************************
+ * @file system_stm32f10x.c
+ * @author MCD Application Team
+ * @version V3.5.0
+ * @date 11-March-2011
+ * @brief CMSIS Cortex-M3 Device Peripheral Access Layer System Source File.
+ *
+ * 1. This file provides two functions and one global variable to be called from
+ * user application:
+ * - SystemInit(): Setups the system clock (System clock source, PLL Multiplier
+ * factors, AHB/APBx prescalers and Flash settings).
+ * This function is called at startup just after reset and
+ * before branch to main program. This call is made inside
+ * the "startup_stm32f10x_xx.s" file.
+ *
+ * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
+ * by the user application to setup the SysTick
+ * timer or configure other parameters.
+ *
+ * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
+ * be called whenever the core clock is changed
+ * during program execution.
+ *
+ * 2. After each device reset the HSI (8 MHz) is used as system clock source.
+ * Then SystemInit() function is called, in "startup_stm32f10x_xx.s" file, to
+ * configure the system clock before to branch to main program.
+ *
+ * 3. If the system clock source selected by user fails to startup, the SystemInit()
+ * function will do nothing and HSI still used as system clock source. User can
+ * add some code to deal with this issue inside the SetSysClock() function.
+ *
+ * 4. The default value of HSE crystal is set to 8 MHz (or 25 MHz, depedning on
+ * the product used), refer to "HSE_VALUE" define in "stm32f10x.h" file.
+ * When HSE is used as system clock source, directly or through PLL, and you
+ * are using different crystal you have to adapt the HSE value to your own
+ * configuration.
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ *
+ ******************************************************************************
+ */
+
+/** @addtogroup CMSIS
+ * @{
+ */
+
+/** @addtogroup stm32f10x_system
+ * @{
+ */
+
+/**
+ * @brief Define to prevent recursive inclusion
+ */
+#ifndef __SYSTEM_STM32F10X_H
+#define __SYSTEM_STM32F10X_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/** @addtogroup STM32F10x_System_Includes
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+
+/** @addtogroup STM32F10x_System_Exported_types
+ * @{
+ */
+
+extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F10x_System_Exported_Constants
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F10x_System_Exported_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F10x_System_Exported_Functions
+ * @{
+ */
+
+extern void SystemInit(void);
+extern void SystemCoreClockUpdate(void);
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__SYSTEM_STM32F10X_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
diff --git a/doc/csv/build_option_codes_en_US.csv b/doc/csv/build_option_codes_en_US.csv
index d77bc150..f7abb8fe 100644
--- a/doc/csv/build_option_codes_en_US.csv
+++ b/doc/csv/build_option_codes_en_US.csv
@@ -6,12 +6,16 @@
"P","Parking motion","Enabled"
"Z","Homing force origin","Enabled"
"H","Homing single axis commands","Enabled"
-"L","Two limit switches on axis","Enabled"
+"T","Two limit switches on axis","Enabled"
"A","Allow feed rate overrides in probe cycles","Enabled"
-"R","Classic compatibility mode","Enabled"
+"D","Use spindle direction as enable pin","Enabled"
+"0","Spindle enable off when speed is zero","Enabled"
+"S","Software limit pin debouncing","Enabled"
+"R","Parking override control","Enabled"
"*","Restore all EEPROM command","Disabled"
"$","Restore EEPROM `$` settings command","Disabled"
"#","Restore EEPROM parameter data command","Disabled"
"I","Build info write user string command","Disabled"
"E","Force sync upon EEPROM write","Disabled"
-"W","Force sync upon work coordinate offset change","Disabled"
\ No newline at end of file
+"W","Force sync upon work coordinate offset change","Disabled"
+"L","Homing initialization auto-lock","Disabled"
\ No newline at end of file
diff --git a/doc/csv/error_codes_en_US.csv b/doc/csv/error_codes_en_US.csv
index a94caf2d..c447054f 100644
--- a/doc/csv/error_codes_en_US.csv
+++ b/doc/csv/error_codes_en_US.csv
@@ -1,4 +1,4 @@
-"Error Code in v1.1+ ","Error Message in v1.0-"," Error Description"
+"Error Code in v1.1+","Error Message in v1.0-","Error Description"
"1","Expected command letter","G-code words consist of a letter and a value. Letter was not found."
"2","Bad number format","Missing the expected G-code word value or numeric value format is not valid."
"3","Invalid statement","Grbl '$' system command was not recognized or supported."
@@ -15,6 +15,7 @@
"14","Line length exceeded","Build info or startup line exceeded EEPROM line length limit. Line not stored."
"15","Travel exceeded","Jog target exceeds machine travel. Jog command has been ignored."
"16","Invalid jog command","Jog command has no '=' or contains prohibited g-code."
+"17","Setting disabled","Laser mode requires PWM output."
"20","Unsupported command","Unsupported or invalid g-code command found in block."
"21","Modal group violation","More than one g-code command from same modal group found in block."
"22","Undefined feed rate","Feed rate has not yet been set or is undefined."
@@ -33,3 +34,4 @@
"35","Invalid gcode ID:35","G2 and G3 arcs require at least one in-plane offset word."
"36","Invalid gcode ID:36","Unused value words found in block."
"37","Invalid gcode ID:37","G43.1 dynamic tool length offset is not assigned to configured tool length axis."
+"38","Invalid gcode ID:38","Tool number greater than max supported value."
\ No newline at end of file
diff --git a/doc/log/commit_log_v1.1.txt b/doc/log/commit_log_v1.1.txt
index 2f6e2794..0717f62c 100644
--- a/doc/log/commit_log_v1.1.txt
+++ b/doc/log/commit_log_v1.1.txt
@@ -1,3 +1,370 @@
+----------------
+Date: 2017-07-31
+Author: Sonny Jeon
+Subject: Hot fix for rare lowering feed override bug.
+
+[fix] Squashed a very rare bug when lowering the feedrate (or rapid) override. When in the very strict set of circumstances with acceleration settings, override step size, and current speed, an internal calculation would cause Grbl to crash. The fix was an overlooked equality statement that should have been a less than or equal, not a less than.
+
+
+----------------
+Date: 2017-07-17
+Author: Sonny Jeon
+Subject: Clean up and new streaming script check-mode feature.
+
+[new] The stream.py streaming script now has a check-mode option, where it will place Grbl in $C check mode automatically and then stream the g-code program. It's a very fast way to check if the g-code program has any errors.
+
+[fix] The debug variable was not initialized if the debug option was enabled in config.h
+
+[fix] Updated error_codes CSV file to the same format as the others.
+
+
+----------------
+Date: 2017-05-31
+Author: chamnit
+Subject: New nonlinear spindle speed PWM output model and solution. Updated scripts.
+
+[new] A nonlinear spindle speed/PWM output option via a piecewise
+linear fit model. Enabled through config.h and solved by a Python
+script in /doc/script
+
+[new] fit_nonlinear_spindle.py. A solver script that can be run on
+http://repl.it for free. No Python install necessary. All instructions
+are available in the script file comments.
+
+[new] stream.py has been updated to include status reports feedback at
+1 second interval.
+
+[fix] stream.py bug fix with verbose mode disabled.
+
+
+----------------
+Date: 2017-03-24
+Author: Sonny Jeon
+Subject: Added an error code for laser mode when VARIABLE_SPINDLE is disabled.
+
+- When trying to enable laser mode with $32=1 and VARIABLE_SPINDLE is
+disabled, the error code shown was improperly stating it was a homing
+failure. Added an new error code specifically for the laser mode being
+disabled without VARIABLE_SPINDLE.
+
+
+----------------
+Date: 2017-03-19
+Author: Sonny Jeon
+Subject: Housekeeping.
+
+- Moved Grbl logo files to a separate repo.
+
+- Added PocketNC FR4 defaults. Needs some additional work though to be
+compatible.
+
+- Updated README image links.
+
+
+----------------
+Date: 2017-03-19
+Author: Sonny Jeon
+Subject: Update README.md
+
+----------------
+Date: 2017-03-02
+Author: Sonny Jeon
+Subject: Fixed $G report issue with M7 and M8 both enabled.
+
+[fix] When M7 and M8 are both enabled, $G report would show `M78`,
+rather than `M7 M8`. This only effects systems that enable M7 mist
+coolant in config.h. Not the default build.
+
+
+----------------
+Date: 2017-02-27
+Author: Sonny Jeon
+Subject: Fixed shared build info code.
+
+- The build info options of “two switches on an axis†and “homing init
+lock†shared the same letter ‘L’. The former is now ’T’.
+
+
+----------------
+Date: 2017-02-23
+Author: Sonny Jeon
+Subject: Restrict coincident target updates to M3 constant laser only.
+
+- Restrict M3 forced updates when there is a motion block with a
+coincident target. Force syncing of the spindle state can lead to some
+pauses during a job that has coincident targets. That’s not
+particularly desirable. This ensures M4 dynamic mode is not effected by
+this force-sync.
+
+
+----------------
+Date: 2017-02-23
+Author: Sonny Jeon
+Subject: Fixed issue with M3 laser state changes and coincident targets.
+
+[fix] When in M3 constant laser power mode, a change from G0 to G1
+would not set the laser on, if G1 was passed with a coincident target.
+Motion controller now checks for a coincident target situation and will
+force a spindle sync when detected.
+
+
+----------------
+Date: 2017-01-31
+Author: Sonny Jeon
+Subject: Additional build info in the $I printout.
+
+- [new] Added total available planner buffer blocks (15 shown, but
+there are 16. one is used by the ring buffer and to execute system
+motions) and serial RX buffer bytes. This information is useful for
+GUIs to setup and optimize their streaming protocols easily.
+
+[doc] Updated the interface document to reflect the change.
+
+
+----------------
+Date: 2017-01-29
+Author: Sonny Jeon
+Subject: Tidying up parking override control implementation
+
+[new] Added a default configuration for the parking override control
+upon a reset or power-up. By default, parking is enabled, but this may
+be disabled via a config.h option.
+
+[fix] Parking override control should be checking if the command word
+is passed, rather than the value.
+
+
+----------------
+Date: 2017-01-28
+Author: chamnit
+Subject: v1.1f. Parking override control. Spindle enable pin option.
+
+[ver] v1.1f update due to tweaks to interface from new parking override
+control.
+
+[new] Parking motion override control via new `M56 P0` and `M56 P1`
+command, which disables and enables the parking motion, respectively.
+Requires ENABLE_PARKING_OVERRIDE_CONTROL and PARKING_ENABLE enabled in
+config.h. Primarily for OEMs.
+
+[new] `M56` appears in the $G report when enabled.
+
+[new] Five new build info identification letters. Some were missing and
+a couple are new. Updated the CSV and documentation to reflect these
+new items.
+
+[new] Spindle enable pin configuration option to alter its behavior
+based on how certain lasers work. By default, Grbl treats the enable
+pin separately and leaves it on when S is 0. The new option turns the
+enable pin on and off with S>0 and S=0. This only is in effect when a
+user enables the USE_SPINDLE_DIR_AS_ENABLE_PIN option.
+
+[fix] M4 is now allowed to work when USE_SPINDLE_DIR_AS_ENABLE_PIN is
+enabled. Previously this was blocked and was problematic for laser
+folks using M4.
+
+[fix] Properly declared system variables as extern. Not sure how that
+went unnoticed or why it worked up until now but it has.
+
+[fix] EXTREMELY RARE. When AMASS is intentionally disabled and sent a
+motion command that is _one step_ in length, Grbl would not actuate the
+step due to numerical round-off. Applied a fix to prevent the round-off
+issue.
+
+[fix] Added a compile-time check for AMASS settings to make sure that
+the numerical round-off issue doesn’t effect it. This would only happen
+if someone set AMASS max levels to zero. It does not effect AMASS with
+its current defaults.
+
+[fix] Wrapped the mc_parking_motion() function in an ifdef for porting
+purposes.
+
+[fix] Fixed an issue when in inverse time mode and G0’s would require a
+F word. This was not correct.
+
+[fix] Added a note in the defaults.h file that MAX_TRAVEL values must
+be positive. Some users were setting this negative and it was causing
+issues.
+
+
+----------------
+Date: 2017-01-14
+Author: Sonny Jeon
+Subject: Tool number bug fix. Updated documentation.
+
+- [fix] Tool numbers were not being tracked and reported correctly. Now
+shows tool number values in $G when programmed.
+
+- [fix] Added a max tool number value check to the g-code parser.
+
+- [doc] Added a new error code for invalid tool number. Updated CSV and
+interface documents.
+
+- [doc] Added a implementation note for buffer state in status reports.
+Don’t rely on this data for streaming.
+
+
+----------------
+Date: 2017-01-03
+Author: Sonny Jeon
+Subject: Spindle enable pin with variable spindle option fix.
+
+- [fix] When USE_SPINDLE_DIR_AS_ENABLE_PIN is enabled in config.h, the
+enable pin was not being set when spindle speed is zero. This behavior
+should now be fixed.
+
+
+----------------
+Date: 2016-12-19
+Author: Sonny Jeon
+Subject: Fixed homing fail alarm handling. Re-integrated software debouncing.
+
+- [bug] Fixed a homing fail issue, where the alarm was not being set
+right, not cleared correctly. It would report the wrong code and enter
+an infinite alarm loop. This was due to how alarm codes were altered a
+while back. Now updated and fixed to show the right codes.
+
+- [feature] Re-installed optional software debouncing for hard limit
+switches. By request.
+
+
+----------------
+Date: 2016-12-18
+Author: Sonny Jeon
+Subject: Addressed optional PWM min value issue. Updated docs.
+
+- [fix] Spindle PWM minimum value had some typos. Fixed the macros to
+compile correctly. Only effects users that enable SPINDLE_MINIMUM_PWM.
+The name changed to SPINDLE_PWM_MIN_VALUE for consistency sake.
+
+- Updated the laser documentation.
+
+
+----------------
+Date: 2016-12-12
+Author: Sonny Jeon
+Subject: Updating steam.py streaming script
+
+- Added push message capability to the stream.py streaming script. It
+prints out as a `Debug:` string in the output.
+
+
+----------------
+Date: 2016-12-11
+Author: Sonny Jeon
+Subject: Updated documentation.
+
+
+----------------
+Date: 2016-12-10
+Author: Sonny Jeon
+Subject: Updated documentation. Cleaned up a bit.
+
+- [doc] Updated the markdown documents for the v1.1 release.
+
+- [doc] Removed references to classic GUI mode.
+
+
+----------------
+Date: 2016-12-09
+Author: Sonny Jeon
+Subject: Update README.md
+
+----------------
+Date: 2016-12-09
+Author: Sonny Jeon
+Subject: Update README.md
+
+----------------
+Date: 2016-12-09
+Author: Sonny Jeon
+Subject: Update README.md
+
+----------------
+Date: 2016-12-08
+Author: Sonny Jeon
+Subject: Removed classic GUI interface. Fixed typo with line number support.
+
+- [config] Permanently removed classic GUI interface support. This
+unintentionally created a problem where some users/GUI devs used this
+compatibility mode and did not update to the new interface. So, there
+were two interfaces in use, rather than just one like it was intended.
+This removal should help everyone by forcing all GUIs to update and
+updated GUI not having to support yet another interface.
+
+- Fixed typo with line number support in jog mode.
+
+
+----------------
+Date: 2016-12-04
+Author: chamnit
+Subject: Fixed unintended laser mode pausing. Updated documentation. Min SS OVR lowered to 10%.
+
+- [laser] Tested a working version and pushed the wrong one for the
+last! 20161203 was pausing upon every spindle speed change. That’s not
+right. Fixed so nearly all motions are passed through and does not stop.
+
+- Minimum spindle speed override lower from 50% to 10%. Lasers could
+use the lower speeds.
+
+- Fixed a very minor bug related to G80 error checking. Allowed no
+error with non-modal motions with axis words. Not correct and fixed.
+
+- Fixed a compile error when disabling VARIABLE_SPINDLE
+
+- [doc] Updated some obsolete documentation.
+
+- [doc] Started a “Laser Mode†document that summarizes how Grbl’s new
+laser mode works.
+
+
+----------------
+Date: 2016-12-03
+Author: Sonny Jeon
+Subject: v1.1e: New laser features. G-code parser refactoring. CoreXY homing fix.
+
+- Increment to v1.1e due to new laser features.
+
+- After several discussions with some prominent laser people, a few
+tweaks to the new laser mode has been installed.
+
+- LASER: M3 behaves in a constant power mode.
+
+- LASER: M4 behaves in a dynamic power mode, where the laser power is
+automatically adjusted based on how fast Grbl is moving relative to the
+programmed feed rate. This is the same as the CONSTANT_POWER_PER_RATE
+config.h option in the last version. NOTE: When not in motion in M4,
+Grbl automatically turns off the laser. Again, it only operates while
+moving!
+
+- LASER: Only G1, G2, and G3 motion modes will turn on the laser. So,
+this means that G0, G80 motion modes will always keep the laser
+disabled. No matter if M3/M4 are active!
+
+- LASER: A spindle stop override is automatically invoked when a laser
+is put in a feed hold. This behavior may be disabled by a config.h
+option.
+
+- Lots of little tweaks to the g-code parser to help streamline it a
+bit. It should no effect how it operates. Generally just added a parser
+flag to track and execute certain scenarios a little more clearly.
+
+- Jog motions now allow line numbers to be passed to it and will be
+displayed in the status reports.
+
+- Fixed a CoreXY homing bug.
+
+- Fixed an issue when $13 is changed, WCO isn’t sent immediately.
+
+- Altered how spindle PWM is set in the stepper ISR. Updated on a step
+segment basis now. May need to change this back if there are any
+oddities from doing this.
+
+- Updated some documentation. Clarified why M0 no longer showing up in
+$G and why a `1.` floating point values are shown with no decimals,
+like so `1`.
+
+
----------------
Date: 2016-11-12
Author: Sonny Jeon
diff --git a/doc/markdown/change_summary.md b/doc/markdown/change_summary.md
index 8c36bad0..7825676f 100644
--- a/doc/markdown/change_summary.md
+++ b/doc/markdown/change_summary.md
@@ -90,9 +90,8 @@ On a final note, these interface tweaks came about out of necessity, because mor
- Overrides are included in every 10 or 20 status reports (configurable) depending on what Grbl is doing or, if an override value or toggle state changes, automatically in the next report.
- There are two override fields:
- `Ov:100,100,100` Organized as feed, rapid, and spindle speed overrides in percent.
- - `T:SFM` with each letter `S`, `F`, and `M` are defined as spindle stop active, flood coolant toggled, and mist coolant toggled, respectively.
-
-
+
+- Accessory states are shown alongside override reports when they are active. Like pin states, an accessory state report `A:SFM` contains a letter indicating an active accessory. Letters `S`, `C`, `F`, and `M` are defined as spindle CW, spindle CCW, flood coolant, and mist coolant, respectively. The pins are directly polled and shown here.
- Line numbers, when enabled in config.h, are omitted when:
@@ -110,4 +109,6 @@ On a final note, these interface tweaks came about out of necessity, because mor
- `$J=line` New jogging commands. This command behaves much like a normal G1 command, but there are some key differences. Jog commands don't alter the g-code parser state, meaning a GUI doesn't have to manage it anymore. Jog commands may be queued and cancelled at any time, where they are automatically flushed from the planner buffer without requiring a reset. See the jogging documentation on how they work and how they may be used to implement a low-latency joystick or rotary dial.
- Laser mode `$` setting - When enabled, laser mode will move through consecutive G1, G2, and G3 motion commands that have different spindle speed values without stopping. A spindle speed of zero will disable the laser without stopping as well. However, when spindle states change, like M3 or M5, stops are still enforced.
- - NOTE: Parking motions are automatically disabled when laser mode is enabled to prevent burning.
\ No newline at end of file
+ - NOTE: Parking motions are automatically disabled when laser mode is enabled to prevent burning.
+
+- `G56 P1` and `G56 P0` - When enabled in config.h with Grbl's parking motion, these commands enable and disable, respectively, the parking motion. Like all override control commands, these commands are modal and are part of the g-code stream.
\ No newline at end of file
diff --git a/doc/markdown/commands.md b/doc/markdown/commands.md
new file mode 100644
index 00000000..5facba9e
--- /dev/null
+++ b/doc/markdown/commands.md
@@ -0,0 +1,345 @@
+# Grbl v1.1 Commands
+
+In general, Grbl assumes all characters and streaming data sent to it is g-code and will parse and try to execute it as soon as it can. However, Grbl also has two separate system command types that are outside of the normal g-code streaming. One system command type is streamed to Grbl like g-code, but starts with a `$` character to tell Grbl it's not g-code. The other is composed of a special set of characters that will immediately command Grbl to do a task in real-time. It's not part of the g-code stream. Grbl's system commands do things like control machine state, report saved parameters or what Grbl is doing, save or print machine settings, run a homing cycle, or make the machine move faster or slower than programmed. This document describes these "internal" system Grbl commands, what they do, how they work, and how to use them.
+
+## Getting Started
+
+First, connect to Grbl using the serial terminal of your choice.
+
+Set the baud rate to **115200** as 8-N-1 (8-bits, no parity, and 1-stop bit.)
+
+Once connected
+ you should get the Grbl-prompt, which looks like this:
+
+```
+Grbl 1.1e ['$' for help]
+```
+
+Type $ and press enter to have Grbl print a help message. You should not see any local echo of the $ and enter. Grbl should respond with:
+
+```
+[HLP:$$ $# $G $I $N $x=val $Nx=line $J=line $SLP $C $X $H ~ ! ? ctrl-x]
+```
+
+The ‘$’-commands are Grbl system commands used to tweak the settings, view or change Grbl's states and running modes, and start a homing cycle. The last four **non**-'$' commands are realtime control commands that can be sent at anytime, no matter what Grbl is doing. These either immediately change Grbl's running behavior or immediately print a report of the important realtime data like current position (aka DRO). There are over a dozen more realtime control commands, but they are not user type-able. See realtime command section for details.
+
+***
+
+## Grbl '$' Commands
+
+The `$` system commands provide additional controls for the user, such as printing feedback on the current G-code parser modal state or running the homing cycle. This section explains what these commands are and how to use them.
+
+#### `$$`and `$x=val` - View and write Grbl settings
+See [Grbl v1.1 Configuration](https://github.com/gnea/grbl/wiki/Grbl-v1.1-Configuration#grbl-settings) for more details on how to view and write setting and learn what they are.
+
+#### `$#` - View gcode parameters
+
+G-code parameters store the coordinate offset values for G54-G59 work coordinates, G28/G30 pre-defined positions, G92 coordinate offset, tool length offsets, and probing (not officially, but we added here anyway). Most of these parameters are directly written to EEPROM anytime they are changed and are persistent. Meaning that they will remain the same, regardless of power-down, until they are explicitly changed. The non-persistent parameters, which will are not retained when reset or power-cycled, are G92, G43.1 tool length offsets, and the G38.2 probing data.
+
+G54-G59 work coordinates can be changed via the `G10 L2 Px` or `G10 L20 Px` command defined by the NIST gcode standard and the EMC2 (linuxcnc.org) standard. G28/G30 pre-defined positions can be changed via the `G28.1` and the `G30.1` commands, respectively.
+
+When `$#` is called, Grbl will respond with the stored offsets from machine coordinates for each system as follows. `TLO` denotes tool length offset (for the default z-axis), and `PRB` denotes the coordinates of the last probing cycle, where the suffix `:1` denotes if the last probe was successful and `:0` as not successful.
+
+```
+[G54:4.000,0.000,0.000]
+[G55:4.000,6.000,7.000]
+[G56:0.000,0.000,0.000]
+[G57:0.000,0.000,0.000]
+[G58:0.000,0.000,0.000]
+[G59:0.000,0.000,0.000]
+[G28:1.000,2.000,0.000]
+[G30:4.000,6.000,0.000]
+[G92:0.000,0.000,0.000]
+[TLO:0.000]
+[PRB:0.000,0.000,0.000:0]
+```
+
+#### `$G` - View gcode parser state
+
+This command prints all of the active gcode modes in Grbl's G-code parser. When sending this command to Grbl, it will reply with a message starting with an `[GC:` indicator like:
+
+```
+[GC:G0 G54 G17 G21 G90 G94 M0 M5 M9 T0 S0.0 F500.0]
+```
+
+These active modes determine how the next G-code block or command will be interpreted by Grbl's G-code parser. For those new to G-code and CNC machining, modes sets the parser into a particular state so you don't have to constantly tell the parser how to parse it. These modes are organized into sets called "modal groups" that cannot be logically active at the same time. For example, the units modal group sets whether your G-code program is interpreted in inches or in millimeters.
+
+A short list of the modal groups, supported by Grbl, is shown below, but more complete and detailed descriptions can be found at LinuxCNC's [website](http://www.linuxcnc.org/docs/2.4/html/gcode_overview.html#sec:Modal-Groups). The G-code commands in **bold** indicate the default modes upon powering-up Grbl or resetting it. The commands in _italics_ indicate a special Grbl-only command.
+
+| Modal Group Meaning | Member Words |
+|:----:|:----:|
+| Motion Mode | **G0**, G1, G2, G3, G38.2, G38.3, G38.4, G38.5, G80 |
+|Coordinate System Select | **G54**, G55, G56, G57, G58, G59|
+|Plane Select | **G17**, G18, G19|
+|Distance Mode | **G90**, G91|
+|Arc IJK Distance Mode | **G91.1** |
+|Feed Rate Mode | G93, **G94**|
+|Units Mode | G20, **G21**|
+|Cutter Radius Compensation | **G40** |
+|Tool Length Offset |G43.1, **G49**|
+|Program Mode | **M0**, M1, M2, M30|
+|Spindle State |M3, M4, **M5**|
+|Coolant State | M7, M8, **M9** |
+|Override Control | _M56_ |
+
+Grbl supports a special _M56_ override control command, where this enables and disables Grbl's parking motion when a `P1` or a `P0` is passed with `M56`, respectively. This command is only available when both parking and this particular option is enabled.
+
+In addition to the G-code parser modes, Grbl will report the active `T` tool number, `S` spindle speed, and `F` feed rate, which all default to 0 upon a reset. For those that are curious, these don't quite fit into nice modal groups, but are just as important for determining the parser state.
+
+#### `$I` - View build info
+This prints feedback to the user the Grbl version and source code build date. Optionally, `$I` can also store a short string to help identify which CNC machine you are communicating with, if you have more than machine using Grbl. To set this string, send Grbl `$I=xxx`, where `xxx` is your customization string that is less than 80 characters. The next time you query Grbl with a `$I` view build info, Grbl will print this string after the version and build date.
+
+NOTE: Some OEMs may block access to over-writing the build info string so they can store product information and codes there.
+
+#### $N - View startup blocks
+
+`$Nx` are the startup blocks that Grbl runs every time you power on Grbl or reset Grbl. In other words, a startup block is a line of G-code that you can have Grbl auto-magically run to set your G-code modal defaults, or anything else you need Grbl to do everytime you start up your machine. Grbl can store two blocks of G-code as a system default.
+
+So, when connected to Grbl, type `$N` and then enter. Grbl should respond with something short like:
+```
+$N0=
+$N1=
+ok
+```
+Not much to go on, but this just means that there is no G-code block stored in line `$N0` for Grbl to run upon startup. `$N1` is the next line to be run.
+
+#### $Nx=line - Save startup block
+
+**IMPORTANT: Be very careful when storing any motion (G0/1,G2/3,G28/30) commands in the startup blocks. These motion commands will run everytime you reset or power up Grbl, so if you have an emergency situation and have to e-stop and reset, a startup block move can and will likely make things worse quickly. Also, do not place any commands that save data to EEPROM, such as G10/G28.1/G30.1. This will cause Grbl to constantly re-write this data upon every startup and reset, which will eventually wear out your Arduino's EEPROM.**
+
+**Typical usage for a startup block is simply to set your preferred modal states, such as G20 inches mode, always default to a different work coordinate system, or, to provide a way for a user to run some user-written unique feature that they need for their crazy project.**
+
+To set a startup block, type `$N0=` followed by a valid G-code block and an enter. Grbl will run the block to check if it's valid and then reply with an `ok` or an `error:` to tell you if it's successful or something went wrong. If there is an error, Grbl will not save it.
+
+For example, say that you want to use your first startup block `$N0` to set your G-code parser modes like G54 work coordinate, G20 inches mode, G17 XY-plane. You would type `$N0=G20 G54 G17` with an enter and you should see an `ok` response. You can then check if it got stored by typing `$N` and you should now see a response like `$N0=G20G54G17`.
+
+Once you have a startup block stored in Grbl's EEPROM, everytime you startup or reset you will see your startup block printed back to you, starting with an open-chevron `>`, and a `:ok` response from Grbl to indicate if it ran okay. So for the previous example, you'll see:
+
+```
+Grbl 1.1d ['$' for help]
+>G20G54G17:ok
+
+```
+If you have multiple G-code startup blocks, they will print back to you in order upon every startup. And if you'd like to clear one of the startup blocks, (e.g., block 0) type `$N0=` without anything following the equal sign.
+
+NOTE: There are two variations on when startup blocks with run. First, it will not run if Grbl initializes up in an ALARM state or exits an ALARM state via an `$X` unlock for safety reasons. Always address and cancel the ALARM and then finish by a reset, where the startup blocks will run at initialization. Second, if you have homing enabled, the startup blocks will execute immediately after a successful homing cycle, not at startup.
+
+#### `$C` - Check gcode mode
+This toggles the Grbl's gcode parser to take all incoming blocks and process them completely, as it would in normal operation, but it does not move any of the axes, ignores dwells, and powers off the spindle and coolant. This is intended as a way to provide the user a way to check how their new G-code program fares with Grbl's parser and monitor for any errors (and checks for soft limit violations, if enabled).
+
+When toggled off, Grbl will perform an automatic soft-reset (^X). This is for two purposes. It simplifies the code management a bit. But, it also prevents users from starting a job when their G-code modes are not what they think they are. A system reset always gives the user a fresh, consistent start.
+
+#### `$X` - Kill alarm lock
+Grbl's alarm mode is a state when something has gone critically wrong, such as a hard limit or an abort during a cycle, or if Grbl doesn't know its position. By default, if you have homing enabled and power-up the Arduino, Grbl enters the alarm state, because it does not know its position. The alarm mode will lock all G-code commands until the '$H' homing cycle has been performed. Or if a user needs to override the alarm lock to move their axes off their limit switches, for example, '$X' kill alarm lock will override the locks and allow G-code functions to work again.
+
+But, tread carefully!! This should only be used in emergency situations. The position has likely been lost, and Grbl may not be where you think it is. So, it's advised to use G91 incremental mode to make short moves. Then, perform a homing cycle or reset immediately afterwards.
+
+As noted earlier, startup lines do not execute after a `$X` command. Always reset when you have cleared the alarm and fixed the scenario that caused it. When Grbl resets to idle, the startup lines will then run as normal.
+
+#### `$H` - Run homing cycle
+This command is the only way to perform the homing cycle in Grbl. Some other motion controllers designate a special G-code command to run a homing cycle, but this is incorrect according to the G-code standards. Homing is a completely separate command handled by the controller.
+
+TIP: After running a homing cycle, rather jogging manually all the time to a position in the middle of your workspace volume. You can set a G28 or G30 pre-defined position to be your post-homing position, closer to where you'll be machining. To set these, you'll first need to jog your machine to where you would want it to move to after homing. Type G28.1 (or G30.1) to have Grbl store that position. So then after '$H' homing, you could just enter 'G28' (or 'G30') and it'll move there auto-magically. In general, I would just move the XY axis to the center and leave the Z-axis up. This ensures that there isn't a chance the tool in the spindle will interfere and that it doesn't catch on anything.
+
+#### `$Jx=line` - Run jogging motion
+
+New to Grbl v1.1, this command will execute a special jogging motion. There are three main differences between a jogging motion and a motion commanded by a g-code line.
+
+- Like normal g-code commands, several jog motions may be queued into the planner buffer, but the jogging can be easily canceled by a jog-cancel or feed-hold real-time command. Grbl will immediately hold the current jog and then automatically purge the buffers of any remaining commands.
+- Jog commands are completely independent of the g-code parser state. It will not change any modes like `G91` incremental distance mode. So, you no longer have to make sure that you change it back to `G90` absolute distance mode afterwards. This helps reduce the chance of starting with the wrong g-code modes enabled.
+- If soft-limits are enabled, any jog command that exceeds a soft-limit will simply return an error. It will not throw an alarm as it would with a normal g-code command. This allows for a much more enjoyable and fluid GUI or joystick interaction.
+
+Executing a jog requires a specific command structure, as described below:
+
+ - The first three characters must be '$J=' to indicate the jog.
+ - The jog command follows immediate after the '=' and works like a normal G1 command.
+ - Feed rate is only interpreted in G94 units per minute. A prior G93 state is ignored during jog.
+ - Required words:
+ - XYZ: One or more axis words with target value.
+ - F - Feed rate value. NOTE: Each jog requires this value and is not treated as modal.
+ - Optional words: Jog executes based on current G20/G21 and G90/G91 g-code parser state. If one of the following optional words is passed, that state is overridden for one command only.
+ - G20 or G21 - Inch and millimeter mode
+ - G90 or G91 - Absolute and incremental distances
+ - G53 - Move in machine coordinates
+ - All other g-codes, m-codes, and value words are not accepted in the jog command.
+ - Spaces and comments are allowed in the command. These are removed by the pre-parser.
+
+ - Example: G21 and G90 are active modal states prior to jogging. These are sequential commands.
+ - `$J=X10.0 Y-1.5` will move to X=10.0mm and Y=-1.5mm in work coordinate frame (WPos).
+ - `$J=G91 G20 X0.5` will move +0.5 inches (12.7mm) to X=22.7mm (WPos). Note that G91 and G20 are only applied to this jog command.
+ - `$J=G53 Y5.0` will move the machine to Y=5.0mm in the machine coordinate frame (MPos). If the work coordinate offset for the y-axis is 2.0mm, then Y is 3.0mm in (WPos).
+
+Jog commands behave almost identically to normal g-code streaming. Every jog command will
+return an 'ok' when the jogging motion has been parsed and is setup for execution. If a
+command is not valid or exceeds a soft-limit, Grbl will return an 'error:'. Multiple jogging commands may be queued in sequence.
+
+NOTE: See additional jogging documentation for details on using this command to create a low-latency joystick or rotary dial interface.
+
+
+#### `$RST=$`, `$RST=#`, and `$RST=*`- Restore Grbl settings and data to defaults
+These commands are not listed in the main Grbl `$` help message, but are available to allow users to restore parts of or all of Grbl's EEPROM data. Note: Grbl will automatically reset after executing one of these commands to ensure the system is initialized correctly.
+
+- `$RST=$` : Erases and restores the `$$` Grbl settings back to defaults, which is defined by the default settings file used when compiling Grbl. Often OEMs will build their Grbl firmwares with their machine-specific recommended settings. This provides users and OEMs a quick way to get back to square-one, if something went awry or if a user wants to start over.
+- `$RST=#` : Erases and zeros all G54-G59 work coordinate offsets and G28/30 positions stored in EEPROM. These are generally the values seen in the `$#` parameters printout. This provides an easy way to clear these without having to do it manually for each set with a `G20 L2/20` or `G28.1/30.1` command.
+- `$RST=*` : This clears and restores all of the EEPROM data used by Grbl. This includes `$$` settings, `$#` parameters, `$N` startup lines, and `$I` build info string. Note that this doesn't wipe the entire EEPROM, only the data areas Grbl uses. To do a complete wipe, please use the Arduino IDE's EEPROM clear example project.
+
+NOTE: Some OEMs may restrict some or all of these commands to prevent certain data they use from being wiped.
+
+#### `$SLP` - Enable Sleep Mode
+
+This command will place Grbl into a de-powered sleep state, shutting down the spindle, coolant, and stepper enable pins and block any commands. It may only be exited by a soft-reset or power-cycle. Once re-initialized, Grbl will automatically enter an ALARM state, because it's not sure where it is due to the steppers being disabled.
+
+This feature is useful if you need to automatically de-power everything at the end of a job by adding this command at the end of your g-code program, BUT, it is highly recommended that you add commands to first move your machine to a safe parking location prior to this sleep command. It also should be emphasized that you should have a reliable CNC machine that will disable everything when its supposed to, like your spindle. Grbl is not responsible for any damage it may cause. It's never a good idea to leave your machine unattended. So, use this command with the utmost caution!
+
+
+***
+
+## Grbl v1.1 Realtime commands
+
+Realtime commands are single control characters that may be sent to Grbl to command and perform an action in real-time. This means that they can be sent at anytime, anywhere, and Grbl will immediately respond, regardless of what it is doing at the time. These commands include a reset, feed hold, resume, status report query, and overrides (in v1.1).
+
+A realtime command:
+
+- Will execute within tens of milliseconds.
+
+- Is a single character that may be sent to Grbl at any time.
+
+- Does not require a line feed or carriage return after them.
+
+- Is not considered a part of the streaming protocol.
+
+- Are intercepted when they are received and never placed in a buffer to be parsed by Grbl.
+
+- Will ignore multiple commands until it has executed the first received command.
+
+- May be tied to an input pin and may be operated with a button or switch.
+
+- Actions depends on state or what Grbl is doing. It may not do anything.
+
+- Descriptions explain how they work and what to expect.
+
+#### ASCII Realtime Command Descriptions
+Four realtime commands are type-able by users on a keyboard and shown in the `$` Grbl help message. These realtime command characters control some of Grbl's basic functions.
+
+- `0x18` (ctrl-x) : Soft-Reset
+
+ - Immediately halts and safely resets Grbl without a power-cycle.
+ - Accepts and executes this command at any time.
+ - If reset while in motion, Grbl will throw an alarm to indicate position may be lost from the motion halt.
+ - If reset while in not motion, position is retained and re-homing is not required.
+ - An input pin is available to connect a button or switch.
+
+
+- `?` : Status Report Query
+
+ - Immediately generates and sends back runtime data with a status report.
+ - Accepts and executes this command at any time, except during a homing cycle and when critical alarm (hard/soft limit error) is thrown.
+
+
+- `~` : Cycle Start / Resume
+
+ - Resumes a feed hold, a safety door/parking state when the door is closed, and the M0 program pause states.
+ - Command is otherwise ignored.
+ - If the parking compile-time option is enabled and the safety door state is ready to resume, Grbl will re-enable the spindle and coolant, move back into position, and then resume.
+ - An input pin is available to connect a button or switch.
+
+
+- `!` : Feed Hold
+
+ - Places Grbl into a suspend or HOLD state. If in motion, the machine will decelerate to a stop and then be suspended.
+ - Command executes when Grbl is in an IDLE, RUN, or JOG state. It is otherwise ignored.
+ - If jogging, a feed hold will cancel the jog motion and flush all remaining jog motions in the planner buffer. The state will return from JOG to IDLE or DOOR, if was detected as ajar during the active hold.
+ - By machine control definition, a feed hold does not disable the spindle or coolant. Only motion.
+ - An input pin is available to connect a button or switch.
+
+
+#### Extended-ASCII Realtime Command Descriptions
+
+Grbl v1.1 installed more than a dozen new realtime commands to control feed, rapid, and spindle overrides. To help prevent users from inadvertently altering overrides with a keystroke and allow for more commands later on, all of the new control characters have been moved to the extended ASCII character set. These are not easily type-able on a keyboard, but, depending on the OS, they may be entered using specific keystroke and code. GUI developers will need to be able to send extended ASCII characters, values `128 (0x80)` to `255 (0xFF)`, to Grbl to take advantage of these new features.
+
+- `0x84` : Safety Door
+
+ - Although typically connected to an input pin to detect the opening of a safety door, this command allows a GUI to enact the safety door behavior with this command.
+ - Immediately suspends into a DOOR state and disables the spindle and coolant. If in motion, the machine will decelerate to a stop and then be suspended.
+ - If executed during homing, Grbl will instead halt motion and throw a homing alarm.
+ - If already in a suspend state or HOLD, the DOOR state supersedes it.
+ - If the parking compile-time option is enabled, Grbl will park the spindle to a specified location.
+ - Command executes when Grbl is in an IDLE, HOLD, RUN, HOMING, or JOG state. It is otherwise ignored.
+ - If jogging, a safety door will cancel the jog and all queued motions in the planner buffer. When the safety door is closed and resumed, Grbl will return to an IDLE state.
+ - An input pin is available to connect a button or switch, if enabled with a compile-time option.
+ - Some builds of Grbl v0.9 used the `@` character for this command, but it was undocumented. Moved to extended-ASCII to prevent accidental commanding.
+
+
+- `0x85` : Jog Cancel
+
+ - Immediately cancels the current jog state by a feed hold and automatically flushing any remaining jog commands in the buffer.
+ - Command is ignored, if not in a JOG state or if jog cancel is already invoked and in-process.
+ - Grbl will return to the IDLE state or the DOOR state, if the safety door was detected as ajar during the cancel.
+
+
+- Feed Overrides
+
+ - Immediately alters the feed override value. An active feed motion is altered within tens of milliseconds.
+ - Does not alter rapid rates, which include G0, G28, and G30, or jog motions.
+ - Feed override value can not be 10% or greater than 200%.
+ - If feed override value does not change, the command is ignored.
+ - Feed override range and increments may be changed in config.h.
+ - The commands are:
+ - `0x90` : Set 100% of programmed rate.
+ - `0x91` : Increase 10%
+ - `0x92` : Decrease 10%
+ - `0x93` : Increase 1%
+ - `0x94` : Decrease 1%
+
+
+- Rapid Overrides
+
+ - Immediately alters the rapid override value. An active rapid motion is altered within tens of milliseconds.
+ - Only effects rapid motions, which include G0, G28, and G30.
+ - If rapid override value does not change, the command is ignored.
+ - Rapid override set values may be changed in config.h.
+ - The commands are:
+ - `0x95` : Set to 100% full rapid rate.
+ - `0x96` : Set to 50% of rapid rate.
+ - `0x97` : Set to 25% of rapid rate.
+
+
+- Spindle Speed Overrides
+
+ - Immediately alters the spindle speed override value. An active spindle speed is altered within tens of milliseconds.
+ - Override values may be changed at any time, regardless of if the spindle is enabled or disabled.
+ - Spindle override value can not be 10% or greater than 200%
+ - If spindle override value does not change, the command is ignored.
+ - Spindle override range and increments may be altered in config.h.
+ - The commands are:
+ - `0x99` : Set 100% of programmed spindle speed
+ - `0x9A` : Increase 10%
+ - `0x9B` : Decrease 10%
+ - `0x9C` : Increase 1%
+ - `0x9D` : Decrease 1%
+
+
+- `0x9E` : Toggle Spindle Stop
+
+ - Toggles spindle enable or disable state immediately, but only while in the HOLD state.
+ - The command is otherwise ignored, especially while in motion. This prevents accidental disabling during a job that can either destroy the part/machine or cause personal injury. Industrial machines handle the spindle stop override similarly.
+ - When motion restarts via cycle start, the last spindle state will be restored and wait 4.0 seconds (configurable) before resuming the tool path. This ensures the user doesn't forget to turn it back on.
+ - While disabled, spindle speed override values may still be altered and will be in effect once the spindle is re-enabled.
+ - If a safety door is opened, the DOOR state will supersede the spindle stop override, where it will manage the spindle re-energizing itself upon closing the door and resuming. The prior spindle stop override state is cleared and reset.
+
+
+- `0xA0` : Toggle Flood Coolant
+
+ - Toggles flood coolant state and output pin until the next toggle or g-code command alters it.
+ - May be commanded at any time while in IDLE, RUN, or HOLD states. It is otherwise ignored.
+ - This override directly changes the coolant modal state in the g-code parser. Grbl will continue to operate normally like it received and executed an `M8` or `M9` g-code command.
+ - When `$G` g-code parser state is queried, the toggle override change will be reflected by an `M8` enabled or disabled with an `M9` or not appearing when `M7` is present.
+
+
+- `0xA1` : Toggle Mist Coolant
+
+ - Enabled by `ENABLE_M7` compile-time option. Default is disabled.
+ - Toggles mist coolant state and output pin until the next toggle or g-code command alters it.
+ - May be commanded at any time while in IDLE, RUN, or HOLD states. It is otherwise ignored.
+ - This override directly changes the coolant modal state in the g-code parser. Grbl will continue to operate normally like it received and executed an `M7` or `M9` g-code command.
+ - When `$G` g-code parser state is queried, the toggle override change will be reflected by an `M7` enabled or disabled with an `M9` or not appearing when `M8` is present.
\ No newline at end of file
diff --git a/doc/markdown/interface.md b/doc/markdown/interface.md
index 424301c4..184603e0 100644
--- a/doc/markdown/interface.md
+++ b/doc/markdown/interface.md
@@ -2,33 +2,125 @@
The interface for Grbl is fairly simple and straightforward. With Grbl v1.1, steps have been taken to try to make it even easier for new users to get started, and for GUI developers to write their own custom interfaces to Grbl.
-In short, Grbl communicates through the serial interface on the Arduino. You just need to connect your Arduino to your computer with a USB cable. Use any standard serial terminal program to connect to Grbl, such as: the Arduino IDE serial monitor, Coolterm, puTTY, etc. Or use one of the many great Grbl GUIs out there in the Internet wild.
+Grbl communicates through the serial interface on the Arduino. You just need to connect your Arduino to your computer with a USB cable. Use any standard serial terminal program to connect to Grbl, such as: the Arduino IDE serial monitor, Coolterm, puTTY, etc. Or use one of the many great Grbl GUIs out there in the Internet wild.
-Just about every user interaction with Grbl is performed by sending it a string of characters, followed by a carriage return. Grbl will then process the string, execute it accordingly, and then reply back with a response message to tell you how it went. These strings include sending Grbl: a G-code block to execute, commands to configure Grbl's system settings, to view how Grbl is doing, etc. At times, Grbl may not respond immediately. This happens only when Grbl is busy doing something else, or waiting for some room to clear in its look-ahead planner buffer so it can finish processing the previous line sent.
+The primary way to talk to Grbl is performed by sending it a string of characters, followed by a carriage return. Grbl will then process the string, set it up for execution, and then reply back with a **response message**, also terminated by a return, to tell you how it went. These command strings include sending Grbl: a G-code block to execute, commands to configure Grbl's system settings, to view how Grbl is doing, etc.
-In other words, both commands sent to Grbl and messages received from Grbl have a format of a single line of characters, terminated by a return. To provide more feedback on what Grbl is doing, additional messages may be "pushed" from Grbl to the user in response to a query or to let the user know something important just happened. Finally, an exception to the command and response interface are Grbl's real-time commands. These commands are single, special characters that may be sent to Grbl at any time to immediately alter or report what its doing and do not have a response message. See the [realtime commands] document to see what they are and how they work.
+To stream a g-code program to Grbl, the basic interface is to send Grbl a line of g-code, then wait for the proper **response message** starting with an `ok` or `error`. This signals Grbl has completed the parsing and executing the command. At times, Grbl may not respond immediately. This happens when Grbl is busy doing something else or waiting to place a commanded motion into the look-ahead planner buffer. Other times, usually at the start of a program, Grbl may quickly respond to several lines, but nothing happens. This occurs when Grbl places a series of commanded motions directly in the planner queue and will try to fill it up completely before starting.
+Along with **response messages**, Grbl has **push messages** to provide more feedback on what Grbl is doing and are also strings terminated by a return. These messages may be "pushed" from Grbl to the user in response to a query or to let the user know something important just happened. These can come at any time, but usually from something like a settings print out when asked to. **Push messages** are easily identified because they don't start with an `ok` or `error` like **response messages** do. They are typically placed in `[]` brackets, `<>` chevrons, start with a `$`, or a specific string of text. These are all defined and described later in this document.
-#### Start Up Message
+Finally, Grbl has **real-time commands** that are invoked by a set of special characters that may be sent at any time and are not part of the basic streaming send-response interface. These cause Grbl to immediately execute the command and typically don't generate a response. These include pausing the current motion, speed up/down everything, toggle the spindle during a job, reset Grbl, or query Grbl for a real-time status report. See the `Commands` document to see what they are and how they work.
-**`Grbl X.Xx ['$' for help]`**
+-------
-The start up message always prints upon startup and after a reset. Whenever you see this message, this also means that Grbl has completed re-initializing all its systems, so everything starts out the same every time you use Grbl.
+# Writing an Interface for Grbl
-* `X.Xx` indicates the major version number, followed by a minor version letter. The major version number indicates the general release, while the letter simply indicates a feature update or addition from the preceding minor version letter.
-* Bug fix revisions are tracked by the build info version number, printed when an `$I` command is sent. These revisions don't update the version number and are given by date revised in year, month, and day, like so `20161014`.
+The general interface for Grbl has been described above, but what's missing is how to run an entire G-code program on Grbl, when it doesn't seem to have an upload feature. This is where this section fits in. Early on, users fiercely requested for flash drive, external RAM, LCD support, joysticks, or network support so they can upload a g-code program and run it directly on Grbl. The general answer to that is, good ideas, but Grbl doesn't need them. Grbl already has nearly all of the tools and features to reliably communicate with a graphical user interface (GUI) or a seperate host interface that provides all those extra bells and whistles. Grbl's base philosophy is to minimize what Grbl should be doing, because, in the end, Grbl needs to be concentrating on producing clean, reliable motion. That's it.
-#### Grbl `$` Help Message
-Every string Grbl receives is assumed to be a G-code block/line for it to execute, except for some special system commands Grbl uses for configuration, provide feedback to the user on what and how it's doing, or perform some task such as a homing cycle. To see a list of these system commands, type `$` followed by an enter, and Grbl will respond with:
+## Streaming a G-Code Program to Grbl
+
+Here we will describe two different streaming methods for Grbl GUIs. One of the main problems with streaming to Grbl is the USB port itself. Arduinos and most all micro controllers use a USB-to-serial converter chip that, at times, behaves strangely and not typically how you'd expect, like USB packet buffering and delays that can wreak havoc to a streaming protocol. Another problem is how to deal with some of the latency and oddities of the PCs themselves, because none of them are truly real-time and always create micro-delays when executing other tasks. Regardless, we've come up with ways to ensure the G-code stream is reliable and simple.
+
+The following streaming protocols require tracking the **response messages** to determine when to send the next g-code line. All **push messages** are not counted toward the streaming protocol and should be handled separately. All real-time command characters can be sent at any time and are never placed in Grbl's RX serial buffer. They are intercepted as they come in and simply sets flags for Grbl to execute them.
+
+#### Streaming Protocol: Simple Send-Response _[Recommended]_
+The send-response streaming protocol is the most fool-proof and simplest method to stream a G-code program to Grbl. The host PC interface simply sends a line of G-code to Grbl and waits for an `ok` or `error:` **response message** before sending the next line of G-code. So, no matter if Grbl needs to wait for room in the look-ahead planner buffer to finish parsing and executing the last line of G-code or if the the host computer is busy doing something, this guarantees both to the host PC and Grbl, the programmed G-code has been sent and received properly. An example of this protocol is published in our `simple_stream.py` script in our repository.
+
+However, it's also the slowest of three outlined streaming protocols. Grbl essentially has two buffers between the execution of steps and the host PC interface. One of them is the serial receive buffer. This briefly stores up to 127 characters of data received from the host PC until Grbl has time to fetch and parse the line of G-code. The other buffer is the look-ahead planner buffer. This buffer stores up to 16 line motions that are acceleration-planned and optimized for step execution. Since the send-response protocol receives a line of G-code while the host PC waits for a response, Grbl's serial receive buffer is usually empty and under-utilized. If Grbl is actively running and executing steps, Grbl will immediately begin to execute and empty the look-ahead planner buffer, while it sends the response to the host PC, waits for the next line from the host PC, upon receiving it, parse and plan it, and add it to the end of the look-ahead buffer.
+
+Although this communication lag may take only a fraction of a second, there is a cumulative effect, because there is a lag with every G-code block sent to Grbl. In certain scenarios, like a G-code program containing lots of sequential, very short, line segments with high feed rates, the cumulative lag can be large enough to empty and starve the look-ahead planner buffer within this time. This could lead to start-stop motion when the streaming can't keep up with G-code program execution. Also, since Grbl can only plan and optimize what's in the look-ahead planner buffer, the performance through these types of motions will never be full-speed, because look-ahead buffer will always be partially full when using this streaming method. If your expected application doesn't contain a lot of these short line segments with high feed rates, this streaming protocol should be more than adequate for a vast majority of applications, is very robust, and is a quick way to get started.
+
+#### Streaming Protocol: Character-Counting _[**Recommended with Reservation**]_
+
+To get the best of both worlds, the simplicity and reliability of the send-response method and assurance of maximum performance with software flow control, we came up with a simple character-counting protocol for streaming a G-code program to Grbl. It works like the send-response method, where the host PC sends a line of G-code for Grbl to execute and waits for a `response message`, but, rather than needing special XON/XOFF characters for flow control, this protocol simply uses Grbl's responses as a way to reliably track how much room there is in Grbl's serial receive buffer. An example of this protocol is outlined in the `stream.py` streaming script in our repo. This protocol is particular useful for very fast machines like laser cutters.
+
+The main difference between this protocol and the others is the host PC needs to maintain a standing count of how many characters it has sent to Grbl and then subtract the number of characters corresponding to the line executed with each Grbl response. Suppose there is a short G-code program that has 5 lines with 25, 40, 31, 58, and 20 characters (counting the line feed and carriage return characters too). We know Grbl has a 128 character serial receive buffer, and the host PC can send up to 128 characters without overflowing the buffer. If we let the host PC send as many complete lines as we can without over flowing Grbl's serial receive buffer, the first three lines of 25, 40, and 31 characters can be sent for a total of 96 characters. When Grbl sends a **response message**, we know the first line has been processed and is no longer in the serial read buffer. As it stands, the serial read buffer now has the 40 and 31 character lines in it for a total of 71 characters. The host PC needs to then determine if it's safe to send the next line without overflowing the buffer. With the next line at 58 characters and the serial buffer at 71 for a total of 129 characters, the host PC will need to wait until more room has cleared from the serial buffer. When the next Grbl **response message** comes in, the second line has been processed and only the third 31 character line remains in the serial buffer. At this point, it's safe to send the remaining last two 58 and 20 character lines of the g-code program for a total of 110.
+
+While seemingly complicated, this character-counting streaming protocol is extremely effective in practice. It always ensures Grbl's serial read buffer is filled, while never overflowing it. It maximizes Grbl's performance by keeping the look-ahead planner buffer full by better utilizing the bi-directional data flow of the serial port, and it's fairly simple to implement as our `stream.py` script illustrates. We have stress-tested this character-counting protocol to extremes and it has not yet failed. Seemingly, only the speed of the serial connection is the limit.
+
+_RESERVATION:_
+
+- _If a g-code line is parsed and generates an error **response message**, a GUI should stop the stream immediately. However, since the character-counting method stuffs Grbl's RX buffer, Grbl will continue reading from the RX buffer and parse and execute the commands inside it. A GUI won't be able to control this. The interim solution is to check all of the g-code via the $C check mode, so all errors are vetted prior to streaming. This will get resolved in later versions of Grbl._
+
+
+## Interacting with Grbl's Systems
+
+Along with streaming a G-code program, there a few more things to consider when writing a GUI for Grbl, such as how to use status reporting, real-time control commands, dealing with EEPROM, and general message handling.
+
+#### Status Reporting
+When a `?` character is sent to Grbl (no additional line feed or carriage return character required), it will immediately respond with something like `` to report its state and current position. The `?` is always picked-off and removed from the serial receive buffer whenever Grbl detects one. So, these can be sent at any time. Also, to make it a little easier for GUIs to pick up on status reports, they are always encased by `<>` chevrons.
+
+Developers can use this data to provide an on-screen position digital-read-out (DRO) for the user and/or to show the user a 3D position in a virtual workspace. We recommend querying Grbl for a `?` real-time status report at no more than 5Hz. 10Hz may be possible, but at some point, there are diminishing returns and you are taxing Grbl's CPU more by asking it to generate and send a lot of position data.
+
+Grbl's status report is fairly simply in organization. It always starts with a word describing the machine state like `IDLE` (descriptions of these are available elsewhere in the Wiki). The following data values are usually in the order listed below and separated by `|` pipe characters, but may not be in the exact order or printed at all. For a complete description of status report formatting, read the _Real-time Status Reports_ section below.
+
+#### Real-Time Control Commands
+The real-time control commands, `~` cycle start/resume, `!` feed hold, `^X` soft-reset, and all of the override commands, all immediately signal Grbl to change its running state. Just like `?` status reports, these control characters are picked-off and removed from the serial buffer when they are detected and do not require an additional line-feed or carriage-return character to operate.
+
+One important note are the override command characters. These are defined in the extended-ASCII character space and are generally not type-able on a keyboard. A GUI must be able to send these 8-bit values to support overrides.
+
+#### EEPROM Issues
+EEPROM access on the Arduino AVR CPUs turns off all of the interrupts while the CPU _writes_ to EEPROM. This poses a problem for certain features in Grbl, particularly if a user is streaming and running a g-code program, since it can pause the main step generator interrupt from executing on time. Most of the EEPROM access is restricted by Grbl when it's in certain states, but there are some things that developers need to know.
+
+* Settings should not be streamed with the character-counting streaming protocols. Only the simple send-response protocol works. This is because during the EEPROM write, the AVR CPU also shuts-down the serial RX interrupt, which means data can get corrupted or lost. This is safe with the send-response protocol, because it's not sending data after commanding Grbl to save data.
+
+For reference:
+* Grbl's EEPROM write commands: `G10 L2`, `G10 L20`, `G28.1`, `G30.1`, `$x=`, `$I=`, `$Nx=`, `$RST=`
+* Grbl's EEPROM read commands: `G54-G59`, `G28`, `G30`, `$$`, `$I`, `$N`, `$#`
+
+#### G-code Error Handling
+
+Grbl's g-code parser is fully standards-compilant with complete error-checking. When a G-code parser detects an error in a G-code block/line, the parser will dump everything in the block from memory and report an `error:` back to the user or GUI. This dump is absolutely the right thing to do, because a g-code line with an error can be interpreted in multiple ways. However, this dump can be problematic, because the bad G-code block may have contained some valuable positioning commands or feed rate settings that the following g-code depends on.
+
+It's highly recommended to do what all professional CNC controllers do when they detect an error in the G-code program, _**halt**_. Don't do anything further until the user has modified the G-code and fixed the error in their program. Otherwise, bad things could happen.
+
+As a service to GUIs, Grbl has a "check G-code" mode, enabled by the `$C` system command. GUIs can stream a G-code program to Grbl, where it will parse it, error-check it, and report `ok`'s and `errors:`'s without powering on anything or moving. So GUIs can pre-check the programs before streaming them for real. To disable the "check G-code" mode, send another `$C` system command and Grbl will automatically soft-reset to flush and re-initialize the G-code parser and the rest of the system. This perhaps should be run in the background when a user first loads a program, before a user sets up his machine. This flushing and re-initialization clears `G92`'s by G-code standard, which some users still incorrectly use to set their part zero.
+
+#### Jogging
+
+As of Grbl v1.1, a new jogging feature is available that accepts incremental, absolute, or absolute override motions, along with a jog cancel real-time command that will automatically feed hold and purge the planner buffer. The most important aspect of the new jogging motion is that it is completely independent from the g-code parser, so GUIs no longer have to ensure the g-code modal states are set back correctly after jogging is complete. See the jogging document for more details on how it works and how you can use it with an analog joystick or rotary dial.
+
+#### Synchronization
+
+For situations when a GUI needs to run a special set of commands for tool changes, auto-leveling, etc, there often needs to be a way to know when Grbl has completed a task and the planner buffer is empty. The absolute simplest way to do this is to insert a `G4 P0.01` dwell command, where P is in seconds and must be greater than 0.0. This acts as a quick force-synchronization and ensures the planner buffer is completely empty before the GUI sends the next task to execute.
+
+-----
+# Message Summary
+
+In v1.1, Grbl's interface protocol has been tweaked in the attempt to make GUI development cleaner, clearer, and hopefully easier. All messages are designed to be deterministic without needing to know the context of the message. Each can be inferred to a much greater degree than before just by the message type, which are all listed below.
+
+- **Response Messages:** Normal send command and execution response acknowledgement. Used for streaming.
+
+ - `ok` : Indicates the command line received was parsed and executed (or set to be executed).
+ - `error:x` : Indicated the command line received contained an error, with an error code `x`, and was purged. See error code section below for definitions.
+
+- **Push Messages:**
+
+ - `< >` : Enclosed chevrons contains status report data.
+ - `Grbl X.Xx ['$' for help]` : Welcome message indicates initialization.
+ - `ALARM:x` : Indicates an alarm has been thrown. Grbl is now in an alarm state.
+ - `$x=val` and `$Nx=line` indicate a settings printout from a `$` and `$N` user query, respectively.
+ - `[MSG:]` : Indicates a non-queried feedback message.
+ - `[GC:]` : Indicates a queried `$G` g-code state message.
+ - `[HLP:]` : Indicates the help message.
+ - `[G54:]`, `[G55:]`, `[G56:]`, `[G57:]`, `[G58:]`, `[G59:]`, `[G28:]`, `[G30:]`, `[G92:]`, `[TLO:]`, and `[PRB:]` messages indicate the parameter data printout from a `$#` user query.
+ - `[VER:]` : Indicates build info and string from a `$I` user query.
+ - `[echo:]` : Indicates an automated line echo from a pre-parsed string prior to g-code parsing. Enabled by config.h option.
+ - `>G54G20:ok` : The open chevron indicates startup line execution. The `:ok` suffix shows it executed correctly without adding an unmatched `ok` response on a new line.
+
+In addition, all `$x=val` settings, `error:`, and `ALARM:` messages no longer contain human-readable strings, but rather codes that are defined in other documents. The `$` help message is also reduced to just showing the available commands. Doing this saves incredible amounts of flash space. Otherwise, the new overrides features would not have fit.
+
+Other minor changes and bug fixes that may effect GUI parsing include:
+
+- Floating point values printed with zero precision do not show a decimal, or look like an integer. This includes spindle speed RPM and feed rate in mm mode.
+- `$G` reports fixed a long time bug with program modal state. It always showed `M0` program pause when running. Now during a normal program run, no program modal state is given until an `M0`, `M2`, or `M30` is active and then the appropriate state will be shown.
+
+On a final note, this interface tweak came about out of necessity, as more data is being sent back from Grbl and it is capable of doing many more things. It's not intended to be altered again in the near future, if at all. This is likely the only and last major change to this. If you have any comments or suggestions before Grbl v1.1 goes to master, please do immediately so we can all vet the new alteration before its installed.
-```
-[HLP:$$ $# $G $I $N $x=val $Nx=line $J=line $SLP $C $X $H ~ ! ? ctrl-x]
-```
-- _**NOTE:** Grbl v1.1's new override real-time commands are not included in the help message. They use the extended-ASCII character set, which are not easily type-able, and require a GUI that supports them. This is for two reasons: Establish enough characters for all of the overrides with extra for later growth, and prevent accidental keystrokes or characters in a g-code file from enacting an override inadvertently._
-* Check out our [Configuring Grbl](https://github.com/grbl/grbl/wiki/Configuring-Grbl-v0.9) wiki page to find out what all of these commands mean and how to use them.
---------
@@ -62,6 +154,7 @@ Every G-code block sent to Grbl and Grbl `$` system command that is terminated w
| **`14`** | (Grbl-Mega Only) Build info or startup line exceeded EEPROM line length limit. |
| **`15`** | Jog target exceeds machine travel. Command ignored. |
| **`16`** | Jog command with no '=' or contains prohibited g-code. |
+| **`17`** | Laser mode disabled. Requires PWM output. |
| **`20`** | Unsupported or invalid g-code command found in block. |
| **`21`** | More than one g-code command from same modal group found in block.|
| **`22`** | Feed rate has not yet been set or is undefined. |
@@ -80,13 +173,16 @@ Every G-code block sent to Grbl and Grbl `$` system command that is terminated w
| **`35`** | A `G2` or `G3` arc, traced with the offset definition, is missing the `IJK` offset word in the selected plane to trace the arc.|
| **`36`** | There are unused, leftover G-code words that aren't used by any command in the block.|
| **`37`** | The `G43.1` dynamic tool length offset command cannot apply an offset to an axis other than its configured axis. The Grbl default axis is the Z-axis.|
+| **`38`** | Tool number greater than max supported value.|
----------------------
# Grbl Push Messages
-Along with the response message to indicate successfully executing a line command sent to Grbl, Grbl provides additional push messages for important feedback of its current state or if something went horribly wrong. These messages are "pushed" from Grbl and may appear at anytime. They are usually in response to a user query or some system event that Grbl needs to tell you about immediately. These push messages are organized into five general classes:
+Along with the response message to indicate successfully executing a line command sent to Grbl, Grbl provides additional push messages for important feedback of its current state or if something went horribly wrong. These messages are "pushed" from Grbl and may appear at anytime. They are usually in response to a user query or some system event that Grbl needs to tell you about immediately. These push messages are organized into six general classes:
+
+- **_Welcome message_** - A unique message to indicate Grbl has initialized.
- **_ALARM messages_** - Means an emergency mode has been enacted and shut down normal use.
@@ -101,6 +197,17 @@ Along with the response message to indicate successfully executing a line comman
------
+#### Welcome Message
+
+**`Grbl X.Xx ['$' for help]`**
+
+The start up message always prints upon startup and after a reset. Whenever you see this message, this also means that Grbl has completed re-initializing all its systems, so everything starts out the same every time you use Grbl.
+
+* `X.Xx` indicates the major version number, followed by a minor version letter. The major version number indicates the general release, while the letter simply indicates a feature update or addition from the preceding minor version letter.
+* Bug fix revisions are tracked by the build info version number, printed when an `$I` command is sent. These revisions don't update the version number and are given by date revised in year, month, and day, like so `20161014`.
+
+-----
+
#### Alarm Message
Alarm is an emergency state. Something has gone terribly wrong when these occur. Typically, they are caused by limit error when the machine has moved or wants to move outside the machine travel and crash into the ends. They also report problems if Grbl is lost and can't guarantee positioning or a probe command has failed. Once in alarm-mode, Grbl will lock out all g-code functionality and accept only a small set of commands. It may even stop everything and force you to acknowledge the problem until you issue Grbl a reset. While in alarm-mode, the user can override the alarm manually with a specific command, which then re-enables g-code so you can move the machine again. This ensures the user knows about the problem and has taken steps to fix or account for it.
@@ -256,10 +363,12 @@ Feedback messages provide non-critical information on what Grbl is doing, what i
- **Queried Feedback Messages:**
- `[GC:]` G-code Parser State Message
- ```
- [GC:G0 G54 G17 G21 G90 G94 M5 M9 T0 F0.0 S0]
- ok
- ```
+
+ ```
+ [GC:G0 G54 G17 G21 G90 G94 M5 M9 T0 F0.0 S0]
+ ok
+ ```
+
- Initiated by the user via a `$G` command. Grbl replies as follows, where the `[GC:` denotes the message type and is followed by a separate `ok` to confirm the `$G` was executed.
- The shown g-code are the current modal states of Grbl's g-code parser. This may not correlate to what is executing since there are usually several motions queued in the planner buffer.
@@ -273,11 +382,14 @@ Feedback messages provide non-critical information on what Grbl is doing, what i
[HLP:$$ $# $G $I $N $x=val $Nx=line $J=line $C $X $H ~ ! ? ctrl-x]
ok
```
+ - _**NOTE:** Grbl v1.1's new override real-time commands are not included in the help message. They use the extended-ASCII character set, which are not easily type-able, and require a GUI that supports them. This is for two reasons: Establish enough characters for all of the overrides with extra for later growth, and prevent accidental keystrokes or characters in a g-code file from enacting an override inadvertently._
+
+
- The `$#` print parameter data query produces a large set of data which shown below and completed by an `ok` response message.
- - Each line of the printout is starts with the data type, a `:`, and followed by the data values. If there is more than one, the order is XYZ axes, separated by commas.
+ - Each line of the printout is starts with the data type, a `:`, and followed by the data values. If there is more than one, the order is XYZ axes, separated by commas.
- ```
+ ```
[G54:0.000,0.000,0.000]
[G55:0.000,0.000,0.000]
[G56:0.000,0.000,0.000]
@@ -292,21 +404,21 @@ Feedback messages provide non-critical information on what Grbl is doing, what i
ok
```
- - The `PRB:` probe parameter message includes an additional `:` and suffix value is a boolean. It denotes whether the last probe cycle was successful or not.
+ - The `PRB:` probe parameter message includes an additional `:` and suffix value is a boolean. It denotes whether the last probe cycle was successful or not.
- `[VER:]` and `[OPT:]`: Indicates build info data from a `$I` user query. These build info messages are followed by an `ok` to confirm the `$I` was executed, like so:
```
- [VER:v1.1d.20161014:Some string]
- [OPT:VL]
+ [VER:v1.1f.20170131:Some string]
+ [OPT:VL,16,128]
ok
```
- The first line `[VER:]` contains the build version and date.
- A string may appear after the second `:` colon. It is a stored EEPROM string a user via a `$I=line` command or OEM can place there for personal use or tracking purposes.
- - The `[OPT:]` line follows immediately after and contains character codes for compile-time options that were either enabled or disabled. The codes are defined below and a CSV file is also provided for quick parsing. This is generally only used for quickly diagnosing firmware bugs or compatibility issues.
+ - The `[OPT:]` line follows immediately after and contains character codes for compile-time options that were either enabled or disabled and two values separated by commas, which indicates the total usable planner blocks and serial RX buffer bytes, respectively. The codes are defined below and a CSV file is also provided for quick parsing. This is generally only used for quickly diagnosing firmware bugs or compatibility issues.
- | `OPT` Code | Setting Description, Units |
+ | `OPT` Code | Setting Description, Units |
|:-------------:|----|
| **`V`** | Variable spindle enabled |
| **`N`** | Line numbers enabled |
@@ -315,16 +427,20 @@ Feedback messages provide non-critical information on what Grbl is doing, what i
| **`P`** | Parking motion enabled |
| **`Z`** | Homing force origin enabled |
| **`H`** | Homing single axis enabled |
-| **`L`** | Two limit switches on axis enabled |
+| **`T`** | Two limit switches on axis enabled |
+| **`D`** | Spindle direction pin used as enable pin |
+| **`0`** | Spindle enable off when speed is zero enabled |
+| **`S`** | Software limit pin debouncing enabled |
+| **`R`** | Parking override control enabled |
| **`A`** | Allow feed rate overrides in probe cycles |
-| **`R`** | Classic compatiblity mode enabled |
| **`*`** | Restore all EEPROM disabled |
| **`$`** | Restore EEPROM `$` settings disabled |
| **`#`** | Restore EEPROM parameter data disabled |
| **`I`** | Build info write user string disabled |
| **`E`** | Force sync upon EEPROM write disabled |
| **`W`** | Force sync upon work coordinate offset change disabled |
-
+| **`L`** | Homing initialization auto-lock disabled |
+
- `[echo:]` : Indicates an automated line echo from a command just prior to being parsed and executed. May be enabled only by a config.h option. Often used for debugging communication issues. A typical line echo message is shown below. A separate `ok` will eventually appear to confirm the line has been parsed and executed, but may not be immediate as with any line command containing motions.
```
[echo:G1X0.540Y10.4F100]
@@ -348,7 +464,7 @@ Feedback messages provide non-critical information on what Grbl is doing, what i
------
-#### Real-time Status reports
+#### Real-time Status Reports
- Contains real-time data of Grbl’s state, position, and other data required independently of the stream.
@@ -456,6 +572,8 @@ Feedback messages provide non-critical information on what Grbl is doing, what i
- The usage of this data is generally for debugging an interface, but is known to be used to control some GUI-specific tasks. While this is disabled by default, GUIs should expect this data field to appear, but they may ignore it, if desired.
+ - IMPORTANT: Do not use this buffer data to control streaming. During a stream, the reported buffer will often be out-dated and may be incorrect by the time it has been received by the GUI. Instead, please use the streaming protocols outlined. They use Grbl's responses as a direct way to accurately determine the buffer state.
+
- NOTE: The buffer state values changed from showing "in-use" blocks or bytes to "available". This change does not require the GUI knowing how many block/bytes Grbl has been compiled with.
- This data field appears:
@@ -563,42 +681,3 @@ Feedback messages provide non-critical information on what Grbl is doing, what i
- It is disabled in the config.h file. No `$` mask setting available.
- If override refresh counter is in-between intermittent reports.
- `WCO:` exists in current report during refresh. Automatically set to try again on next report.
-
-
--------
-# Message Summary
-
-Grbl v1.1's interface protocol has been tweaked in the attempt to make GUI development cleaner, clearer, and hopefully easier. All messages are designed to be deterministic without needing to know the context of the message. Each can be inferred to a much greater degree than before just by the message type, which are all listed below.
-
-- `ok` / `error:x` : Normal send command and execution response acknowledgement. Used for streaming.
-
-- `< >` : Enclosed chevrons contains status report data.
-
-- `Grbl X.Xx ['$' for help]` : Welcome message indicates initialization.
-
-- `ALARM:x` : Indicates an alarm has been thrown. Grbl is now in an alarm state.
-
-- `$x=val` and `$Nx=line` indicate a settings printout from a `$` and `$N` user query, respectively.
-
-- `[MSG:]` : Indicates a non-queried feedback message.
-
-- `[GC:]` : Indicates a queried `$G` g-code state message.
-
-- `[HLP:]` : Indicates the help message.
-
-- `[G54:]`, `[G55:]`, `[G56:]`, `[G57:]`, `[G58:]`, `[G59:]`, `[G28:]`, `[G30:]`, `[G92:]`, `[TLO:]`, and `[PRB:]` messages indicate the parameter data printout from a `$#` user query.
-
-- `[VER:]` : Indicates build info and string from a `$I` user query.
-
-- `[echo:]` : Indicates an automated line echo from a pre-parsed string prior to g-code parsing. Enabled by config.h option.
-
-- `>G54G20:ok` : The open chevron indicates startup line execution. The `:ok` suffix shows it executed correctly without adding an unmatched `ok` response on a new line.
-
-In addition, all `$x=val` settings, `error:`, and `ALARM:` messages no longer contain human-readable strings, but rather codes that are defined in other documents. The `$` help message is also reduced to just showing the available commands. Doing this saves incredible amounts of flash space. Otherwise, the new overrides features would not have fit.
-
-Other minor changes and bug fixes that may effect GUI parsing include:
-
-- Floating point values printed with zero precision do not show a decimal, or look like an integer. This includes spindle speed RPM and feed rate in mm mode.
-- `$G` reports fixed a long time bug with program modal state. It always showed `M0` program pause when running. Now during a normal program run, no program modal state is given until an `M0`, `M2`, or `M30` is active and then the appropriate state will be shown.
-
-On a final note, this interface tweak came about out of necessity, as more data is being sent back from Grbl and it is capable of doing many more things. It's not intended to be altered again in the near future, if at all. This is likely the only and last major change to this. If you have any comments or suggestions before Grbl v1.1 goes to master, please do immediately so we can all vet the new alteration before its installed.
diff --git a/doc/markdown/jogging.md b/doc/markdown/jogging.md
index 91c71f67..c20aaee2 100644
--- a/doc/markdown/jogging.md
+++ b/doc/markdown/jogging.md
@@ -1,5 +1,7 @@
# Grbl v1.1 Jogging
+This document outlines how to use Grbl v1.1's new jogging commands. These command differ because they can be cancelled and all queued motions are automatically purged with a simple jog-cancel or feed hold real-time command. Jogging command do not alter the g-code parser state in any way, so you no longer have to worry if you remembered to set the distance mode back to `G90` prior to starting a job. Also, jogging works well with an analog joysticks and rotary dials! See the implementation notes below.
+
## How to Use
Executing a jog requires a specific command structure, as described below:
diff --git a/doc/markdown/laser_mode.md b/doc/markdown/laser_mode.md
new file mode 100644
index 00000000..4e42ba3b
--- /dev/null
+++ b/doc/markdown/laser_mode.md
@@ -0,0 +1,89 @@
+## Grbl v1.1 Laser Mode
+
+**_DISCLAIMER: Lasers are extremely dangerous devices. They can instantly cause fires and permanently damage your vision. Please read and understand all related documentation for your laser prior to using it. The Grbl project is not resposible for any damage or issues the firmware may cause, as defined by its GPL license._**
+
+----
+
+Outlined in this document is how Grbl alters its running conditions for the new laser mode to provide both improved performance and attempting to enforce some basic user safety precautions.
+
+## Laser Mode Overview
+
+The main difference between default Grbl operation and the laser mode is how the spindle/laser output is controlled with motions involved. Every time a spindle state `M3 M4 M5` or spindle speed `Sxxx` is altered, Grbl would come to a stop, allow the spindle to change, and then continue. This is the normal operating procedure for a milling machine spindle. It needs time to change speeds.
+
+However, if a laser starts and stops like this for every spindle change, this leads to scorching and uneven cutting/engraving! Grbl's new laser mode prevents unnecessary stops whenever possible and adds a new dynamic laser power mode that automagically scales power based on current speed related to programmed rate. So, you can get super clean and crisp results, even on a low-acceleration machine!
+
+Enabling or disabling Grbl's laser mode is easy. Just alter the **$32** Grbl setting.
+- **To Enable**: Send Grbl a `$32=1` command.
+- **To Disable:** Send Grbl a `$32=0` command.
+
+**WARNING:** If you switch back from laser mode to a spindle for milling, you **MUST** disable laser mode by sending Grbl a `$32=0` command. Milling operations require the spindle to get up to the right rpm to cut correctly and to be **safe**, helping to prevent a tool from breaking and flinging metal shards everywhere. With laser mode disabled, Grbl will briefly pause upon any spindle speed or state change to give the spindle a chance to get up to speed before continuing.
+
+
+## Laser Mode Operation
+
+When laser mode is enabled, Grbl controls laser power by varying the **0-5V** voltage from the spindle PWM D11 pin. **0V** should be treated as disabled, while **5V** is full power. Intermediate output voltages are also assumed to be linear with laser power, such that **2.5V** is approximate 50% laser power. (A compile time option exists to shift this linear model to start at a non-zero voltage.)
+
+By default, the spindle PWM frequency is **1kHz**, which is the recommended PWM frequency for most current Grbl-compatible lasers system. If a different frequency is required, this may be altered by editing the `cpu_map.h` file.
+
+The laser is enabled with the `M3` spindle CW and `M4` spindle CCW commands. These enable two different laser modes that are advantageous for different reasons each.
+
+- **`M3` Constant Laser Power Mode:**
+
+ - Constant laser power mode simply keeps the laser power as programmed, regardless if the machine is moving, accelerating, or stopped. This provides better control of the laser state. With a good G-code program, this can lead to more consistent cuts in more difficult materials.
+
+ - For a clean cut and prevent scorching with `M3` constant power mode, it's a good idea to add lead-in and lead-out motions around the line you want to cut to give some space for the machine to accelerate and decelerate.
+
+ - NOTE: `M3` can be used to keep the laser on for focusing.
+
+- **`M4` Dynamic Laser Power Mode:**
+ - Dynamic laser power mode will automatically adjust laser power based on the current speed relative to the programmed rate. It essentially ensures the amount of laser energy along a cut is consistent even though the machine may be stopped or actively accelerating. This is very useful for clean, precise engraving and cutting on simple materials across a large range of G-code generation methods by CAM programs. It will generally run faster and may be all you need to use.
+
+ - Grbl calculates laser power based on the assumption that laser power is linear with speed and the material. Often, this is not the case. Lasers can cut differently at varying power levels and some materials may not cut well at a particular speed and/power. In short, this means that dynamic power mode may not work for all situations. Always do a test piece prior to using this with a new material or machine.
+
+ - When not in motion, `M4` dynamic mode turns off the laser. It only turns on when the machine moves. This generally makes the laser safer to operate, because, unlike `M3`, it will never burn a hole through your table, if you stop and forget to turn `M3` off in time.
+
+Describe below are the operational changes to Grbl when laser mode is enabled. Please read these carefully and understand them fully, because nothing is worse than a garage _**fire**_.
+
+- Grbl will move continuously through **consecutive** motion commands when programmed with a new `S` spindle speed (laser power). The spindle PWM pin will be updated instantaneously through each motion without stopping.
+ - Example: The following set of g-code commands will not pause between each of them when laser mode is enabled, but will pause when disabled.
+
+ ```
+ G1 X10 S100 F50
+ G1 X0 S90
+ G2 X0 I5 S80
+ ```
+ - Grbl will enforce a laser mode motion stop in a few circumstances. Primarily to ensure alterations stay in sync with the g-code program.
+
+ - Any `M3`, `M4`, `M5` spindle state _change_.
+ - `M3` only and no motion programmed: A `S` spindle speed _change_.
+ - `M3` only and no motion programmed: A `G1 G2 G3` laser powered state _change_ to `G0 G80` laser disabled state.
+ - NOTE: `M4` does not stop for anything but a spindle state _change_.
+
+- The laser will only turn on when Grbl is in a `G1`, `G2`, or `G3` motion mode.
+
+ - In other words, a `G0` rapid motion mode or `G38.x` probe cycle will never turn on and always disable the laser, but will still update the running modal state. When changed to a `G1 G2 G3` modal state, Grbl will immediately enable the laser based on the current running state.
+
+ - Please remember that `G0` is the default motion mode upon power up and reset. You will need to alter it to `G1`, `G2`, or `G3` if you want to manually turn on your laser. This is strictly a safety measure.
+
+ - Example: `G0 M3 S1000` will not turn on the laser, but will set the laser modal state to `M3` enabled and power of `S1000`. A following `G1` command will then immediately be set to `M3` and `S1000`.
+
+ - To have the laser powered during a jog motion, first enable a valid motion mode and spindle state. The following jog motions will inherit and maintain the previous laser state. Please use with caution though. This ability is primarily to allow turning on the laser on a _very low_ power to use the laser dot to jog and visibly locate the start position of a job.
+
+
+- An `S0` spindle speed of zero will turn off the laser. When programmed with a valid laser motion, Grbl will disable the laser instantaneously without stopping for the duration of that motion and future motions until set greater than zero..
+
+ - `M3` constant laser mode, this is a great way to turn off the laser power while continuously moving between a `G1` laser motion and a `G0` rapid motion without having to stop. Program a short `G1 S0` motion right before the `G0` motion and a `G1 Sxxx` motion is commanded right after to go back to cutting.
+
+
+-----
+###CAM Developer Implementation Notes
+
+TODO: Add some suggestions on how to write laser G-code for Grbl.
+
+- When using `M3` constant laser power mode, try to avoid force-sync conditions during a job whenever possible. Basically every spindle speed change must be accompanied by a valid motion. Any motion is fine, since Grbl will automatically enable and disable the laser based on the modal state. Avoid a `G0` and `G1` command with no axis words in this mode and in the middle of a job.
+
+- Ensure smooth motions throughout by turning the laser on and off without an `M3 M4 M5` spindle state command. There are two ways to do this:
+
+ - _Program a zero spindle speed `S0`_: `S0` is valid G-code and turns off the spindle/laser without changing the spindle state. In laser mode, Grbl will smoothly move through consecutive motions and turn off the spindle. Conversely, you can turn on the laser with a spindle speed `S` greater than zero. Remember that `M3` constant power mode requires any spindle speed `S` change to be programmed with a motion to allow continuous motion, while `M4` dynamic power mode does not.
+
+ - _Program an unpowered motion between powered motions_: If you are traversing between parts of a raster job that don't need to have the laser powered, program a `G0` rapid between them. `G0` enforces the laser to be disabled automatically. The last spindle speed programmed doesn't change, so if a valid powered motion, like a `G1` is executed after, it'll immediately re-power the laser with the last programmed spindle speed when executing that motion.
diff --git a/doc/markdown/realtime_cmds.md b/doc/markdown/realtime_cmds.md
index cf6de094..06b1c1d8 100644
--- a/doc/markdown/realtime_cmds.md
+++ b/doc/markdown/realtime_cmds.md
@@ -85,7 +85,7 @@ Grbl v1.1 installed more than a dozen new realtime commands to control feed, rap
- Immediately alters the feed override value. An active feed motion is altered within tens of milliseconds.
- Does not alter rapid rates, which include G0, G28, and G30, or jog motions.
- - Feed override value can not be 1% or greater than 200%
+ - Feed override value can not be 10% or greater than 200%.
- If feed override value does not change, the command is ignored.
- Feed override range and increments may be changed in config.h.
- The commands are:
@@ -112,7 +112,7 @@ Grbl v1.1 installed more than a dozen new realtime commands to control feed, rap
- Immediately alters the spindle speed override value. An active spindle speed is altered within tens of milliseconds.
- Override values may be changed at any time, regardless of if the spindle is enabled or disabled.
- - Spindle override value can not be 50% or greater than 200%
+ - Spindle override value can not be 10% or greater than 200%
- If spindle override value does not change, the command is ignored.
- Spindle override range and increments may be altered in config.h.
- The commands are:
diff --git a/doc/markdown/settings.md b/doc/markdown/settings.md
index 17ee1857..4b54746f 100644
--- a/doc/markdown/settings.md
+++ b/doc/markdown/settings.md
@@ -1,12 +1,3 @@
-#### _Quick-Links:_
-* [Getting Started](https://github.com/grbl/grbl/wiki/Configuring-Grbl-v0.9#getting-started)
-* [Grbl Settings](https://github.com/grbl/grbl/wiki/Configuring-Grbl-v0.9#grbl-settings)
-* [Grbl's Settings and What They Mean](https://github.com/grbl/grbl/wiki/Configuring-Grbl-v0.9#grbls-xval-settings-and-what-they-mean)
-* [Grbl's Other `$` Commands](https://github.com/grbl/grbl/wiki/Configuring-Grbl-v0.9#grbls-other--commands)
-* [Real-Time Commands](https://github.com/grbl/grbl/wiki/Configuring-Grbl-v0.9#real-time-commands----and-ctrl-x)
-
-***
-
## Getting Started
First, connect to Grbl using the serial terminal of your choice.
@@ -232,9 +223,9 @@ This sets the spindle speed for the minimum 0.02V PWM pin output (0V is disabled
#### $32 - Laser mode, boolean
-When enabled, Grbl will move continuously through consecutive `G1`, `G2`, or `G3` motion commands when programmed with a `S` spindle speed (laser power). The spindle PWM pin will be updated instantaneously through each motion without stopping. However, Grbl will still stop motion if a spindle state is commanded and altered, like `M3`, `M4`, or `M5`. If the spindle needs to be disabled while under continuous motion, program a `S0`, zero spindle speed, to disable the spindle with a supported motion command.
+When enabled, Grbl will move continuously through consecutive `G1`, `G2`, or `G3` motion commands when programmed with a `S` spindle speed (laser power). The spindle PWM pin will be updated instantaneously through each motion without stopping. Please read the Grbl laser documentation and your laser device documentation prior to using this mode. Lasers are very dangerous. They can instantly damage your vision permanantly and cause fires. Grbl does not assume any responsibility for any issues the firmware may cause, as defined by its GPL license.
-When disabled, Grbl will operate as it always has, stopping motion with every `S` spindle speed command. This is the normal operating
+When disabled, Grbl will operate as it always has, stopping motion with every `S` spindle speed command. This is the default operation of a milling machine to allow a pause to let the spindle change speeds.
#### $100, $101 and $102 – [X,Y,Z] steps/mm
@@ -266,172 +257,3 @@ Again, like the max rate setting, the simplest way to determine the values for t
#### $130, $131, $132 – [X,Y,Z] Max travel, mm
This sets the maximum travel from end to end for each axis in mm. This is only useful if you have soft limits (and homing) enabled, as this is only used by Grbl's soft limit feature to check if you have exceeded your machine limits with a motion command.
-
-***
-
-## Grbl's Other '$' Commands
-
-The other `$` commands provide additional controls for the user, such as printing feedback on the current G-code parser modal state or running the homing cycle. This section explains what these commands are and how to use them.
-
-#### `$#` - View gcode parameters
-
-G-code parameters store the coordinate offset values for G54-G59 work coordinates, G28/G30 pre-defined positions, G92 coordinate offset, tool length offsets, and probing (not officially, but we added here anyway). Most of these parameters are directly written to EEPROM anytime they are changed and are persistent. Meaning that they will remain the same, regardless of power-down, until they are explicitly changed. The non-persistent parameters, which will are not retained when reset or power-cycled, are G92, G43.1 tool length offsets, and the G38.2 probing data.
-
-G54-G59 work coordinates can be changed via the `G10 L2 Px` or `G10 L20 Px` command defined by the NIST gcode standard and the EMC2 (linuxcnc.org) standard. G28/G30 pre-defined positions can be changed via the `G28.1` and the `G30.1` commands, respectively.
-
-When `$#` is called, Grbl will respond with the stored offsets from machine coordinates for each system as follows. `TLO` denotes tool length offset (for the default z-axis), and `PRB` denotes the coordinates of the last probing cycle, where the suffix `:1` denotes if the last probe was successful and `:0` as not successful.
-
-```
-[G54:4.000,0.000,0.000]
-[G55:4.000,6.000,7.000]
-[G56:0.000,0.000,0.000]
-[G57:0.000,0.000,0.000]
-[G58:0.000,0.000,0.000]
-[G59:0.000,0.000,0.000]
-[G28:1.000,2.000,0.000]
-[G30:4.000,6.000,0.000]
-[G92:0.000,0.000,0.000]
-[TLO:0.000]
-[PRB:0.000,0.000,0.000:0]
-```
-
-#### `$G` - View gcode parser state
-
-This command prints all of the active gcode modes in Grbl's G-code parser. When sending this command to Grbl, it will reply with a message starting with an `[GC:` indicator like:
-
-```
-[GC:G0 G54 G17 G21 G90 G94 M0 M5 M9 T0 S0.0 F500.0]
-```
-
-These active modes determine how the next G-code block or command will be interpreted by Grbl's G-code parser. For those new to G-code and CNC machining, modes sets the parser into a particular state so you don't have to constantly tell the parser how to parse it. These modes are organized into sets called "modal groups" that cannot be logically active at the same time. For example, the units modal group sets whether your G-code program is interpreted in inches or in millimeters.
-
-A short list of the modal groups, supported by Grbl, is shown below, but more complete and detailed descriptions can be found at LinuxCNC's [website](http://www.linuxcnc.org/docs/2.4/html/gcode_overview.html#sec:Modal-Groups). The G-code commands in **bold** indicate the default modes upon powering-up Grbl or resetting it.
-
-| Modal Group Meaning | Member Words |
-|:----:|:----:|
-| Motion Mode | **G0**, G1, G2, G3, G38.2, G38.3, G38.4, G38.5, G80 |
-|Coordinate System Select | **G54**, G55, G56, G57, G58, G59|
-|Plane Select | **G17**, G18, G19|
-|Distance Mode | **G90**, G91|
-|Arc IJK Distance Mode | **G91.1** |
-|Feed Rate Mode | G93, **G94**|
-|Units Mode | G20, **G21**|
-|Cutter Radius Compensation | **G40** |
-|Tool Length Offset |G43.1, **G49**|
-|Program Mode | **M0**, M1, M2, M30|
-|Spindle State |M3, M4, **M5**|
-|Coolant State | M7, M8, **M9** |
-
-In addition to the G-code parser modes, Grbl will report the active `T` tool number, `S` spindle speed, and `F` feed rate, which all default to 0 upon a reset. For those that are curious, these don't quite fit into nice modal groups, but are just as important for determining the parser state.
-
-#### `$I` - View build info
-This prints feedback to the user the Grbl version and source code build date. Optionally, `$I` can also store a short string to help identify which CNC machine you are communicating with, if you have more than machine using Grbl. To set this string, send Grbl `$I=xxx`, where `xxx` is your customization string that is less than 80 characters. The next time you query Grbl with a `$I` view build info, Grbl will print this string after the version and build date.
-
-NOTE: Some OEMs may block access to over-writing the build info string so they can store product information and codes there.
-
-#### $N - View startup blocks
-
-`$Nx` are the startup blocks that Grbl runs every time you power on Grbl or reset Grbl. In other words, a startup block is a line of G-code that you can have Grbl auto-magically run to set your G-code modal defaults, or anything else you need Grbl to do everytime you start up your machine. Grbl can store two blocks of G-code as a system default.
-
-So, when connected to Grbl, type `$N` and then enter. Grbl should respond with something short like:
-```
-$N0=
-$N1=
-ok
-```
-Not much to go on, but this just means that there is no G-code block stored in line `$N0` for Grbl to run upon startup. `$N1` is the next line to be run.
-
-#### $Nx=line - Save startup block
-
-**IMPORTANT: Be very careful when storing any motion (G0/1,G2/3,G28/30) commands in the startup blocks. These motion commands will run everytime you reset or power up Grbl, so if you have an emergency situation and have to e-stop and reset, a startup block move can and will likely make things worse quickly. Also, do not place any commands that save data to EEPROM, such as G10/G28.1/G30.1. This will cause Grbl to constantly re-write this data upon every startup and reset, which will eventually wear out your Arduino's EEPROM.**
-
-**Typical usage for a startup block is simply to set your preferred modal states, such as G20 inches mode, always default to a different work coordinate system, or, to provide a way for a user to run some user-written unique feature that they need for their crazy project.**
-
-To set a startup block, type `$N0=` followed by a valid G-code block and an enter. Grbl will run the block to check if it's valid and then reply with an `ok` or an `error:` to tell you if it's successful or something went wrong. If there is an error, Grbl will not save it.
-
-For example, say that you want to use your first startup block `$N0` to set your G-code parser modes like G54 work coordinate, G20 inches mode, G17 XY-plane. You would type `$N0=G20 G54 G17` with an enter and you should see an `ok` response. You can then check if it got stored by typing `$N` and you should now see a response like `$N0=G20G54G17`.
-
-Once you have a startup block stored in Grbl's EEPROM, everytime you startup or reset you will see your startup block printed back to you, starting with an open-chevron `>`, and a `:ok` response from Grbl to indicate if it ran okay. So for the previous example, you'll see:
-
-```
-Grbl 1.1d ['$' for help]
->G20G54G17:ok
-
-```
-If you have multiple G-code startup blocks, they will print back to you in order upon every startup. And if you'd like to clear one of the startup blocks, (e.g., block 0) type `$N0=` without anything following the equal sign.
-
-NOTE: There are two variations on when startup blocks with run. First, it will not run if Grbl initializes up in an ALARM state or exits an ALARM state via an `$X` unlock for safety reasons. Always address and cancel the ALARM and then finish by a reset, where the startup blocks will run at initialization. Second, if you have homing enabled, the startup blocks will execute immediately after a successful homing cycle, not at startup.
-
-#### `$C` - Check gcode mode
-This toggles the Grbl's gcode parser to take all incoming blocks and process them completely, as it would in normal operation, but it does not move any of the axes, ignores dwells, and powers off the spindle and coolant. This is intended as a way to provide the user a way to check how their new G-code program fares with Grbl's parser and monitor for any errors (and checks for soft limit violations, if enabled).
-
-When toggled off, Grbl will perform an automatic soft-reset (^X). This is for two purposes. It simplifies the code management a bit. But, it also prevents users from starting a job when their G-code modes are not what they think they are. A system reset always gives the user a fresh, consistent start.
-
-#### `$X` - Kill alarm lock
-Grbl's alarm mode is a state when something has gone critically wrong, such as a hard limit or an abort during a cycle, or if Grbl doesn't know its position. By default, if you have homing enabled and power-up the Arduino, Grbl enters the alarm state, because it does not know its position. The alarm mode will lock all G-code commands until the '$H' homing cycle has been performed. Or if a user needs to override the alarm lock to move their axes off their limit switches, for example, '$X' kill alarm lock will override the locks and allow G-code functions to work again.
-
-But, tread carefully!! This should only be used in emergency situations. The position has likely been lost, and Grbl may not be where you think it is. So, it's advised to use G91 incremental mode to make short moves. Then, perform a homing cycle or reset immediately afterwards.
-
-As noted earlier, startup lines do not execute after a `$X` command. Always reset when you have cleared the alarm and fixed the scenario that caused it. When Grbl resets to idle, the startup lines will then run as normal.
-
-#### `$H` - Run homing cycle
-This command is the only way to perform the homing cycle in Grbl. Some other motion controllers designate a special G-code command to run a homing cycle, but this is incorrect according to the G-code standards. Homing is a completely separate command handled by the controller.
-
-TIP: After running a homing cycle, rather jogging manually all the time to a position in the middle of your workspace volume. You can set a G28 or G30 pre-defined position to be your post-homing position, closer to where you'll be machining. To set these, you'll first need to jog your machine to where you would want it to move to after homing. Type G28.1 (or G30.1) to have Grbl store that position. So then after '$H' homing, you could just enter 'G28' (or 'G30') and it'll move there auto-magically. In general, I would just move the XY axis to the center and leave the Z-axis up. This ensures that there isn't a chance the tool in the spindle will interfere and that it doesn't catch on anything.
-
-#### `$Jx=line` - Run jogging motion
-
-New to Grbl v1.1, this command will execute a special jogging motion. There are three main differences between a jogging motion and a motion commanded by a g-code line.
-
-- Like normal g-code commands, several jog motions may be queued into the planner buffer, but the jogging can be easily canceled by a jog-cancel or feed-hold real-time command. Grbl will immediately hold the current jog and then automatically purge the buffers of any remaining commands.
-- Jog commands are completely independent of the g-code parser state. It will not change any modes like `G91` incremental distance mode. So, you no longer have to make sure that you change it back to `G90` absolute distance mode afterwards. This helps reduce the chance of starting with the wrong g-code modes enabled.
-- If soft-limits are enabled, any jog command that exceeds a soft-limit will simply return an error. It will not throw an alarm as it would with a normal g-code command. This allows for a much more enjoyable and fluid GUI or joystick interaction.
-
-Executing a jog requires a specific command structure, as described below:
-
- - The first three characters must be '$J=' to indicate the jog.
- - The jog command follows immediate after the '=' and works like a normal G1 command.
- - Feed rate is only interpreted in G94 units per minute. A prior G93 state is ignored during jog.
- - Required words:
- - XYZ: One or more axis words with target value.
- - F - Feed rate value. NOTE: Each jog requires this value and is not treated as modal.
- - Optional words: Jog executes based on current G20/G21 and G90/G91 g-code parser state. If one of the following optional words is passed, that state is overridden for one command only.
- - G20 or G21 - Inch and millimeter mode
- - G90 or G91 - Absolute and incremental distances
- - G53 - Move in machine coordinates
- - All other g-codes, m-codes, and value words are not accepted in the jog command.
- - Spaces and comments are allowed in the command. These are removed by the pre-parser.
-
- - Example: G21 and G90 are active modal states prior to jogging. These are sequential commands.
- - `$J=X10.0 Y-1.5` will move to X=10.0mm and Y=-1.5mm in work coordinate frame (WPos).
- - `$J=G91 G20 X0.5` will move +0.5 inches (12.7mm) to X=22.7mm (WPos). Note that G91 and G20 are only applied to this jog command.
- - `$J=G53 Y5.0` will move the machine to Y=5.0mm in the machine coordinate frame (MPos). If the work coordinate offset for the y-axis is 2.0mm, then Y is 3.0mm in (WPos).
-
-Jog commands behave almost identically to normal g-code streaming. Every jog command will
-return an 'ok' when the jogging motion has been parsed and is setup for execution. If a
-command is not valid or exceeds a soft-limit, Grbl will return an 'error:'. Multiple jogging commands may be queued in sequence.
-
-NOTE: See additional jogging documentation for details on using this command to create a low-latency joystick or rotary dial interface.
-
-
-#### `$RST=$`, `$RST=#`, and `$RST=*`- Restore Grbl settings and data to defaults
-These commands are not listed in the main Grbl `$` help message, but are available to allow users to restore parts of or all of Grbl's EEPROM data. Note: Grbl will automatically reset after executing one of these commands to ensure the system is initialized correctly.
-
-- `$RST=$` : Erases and restores the `$$` Grbl settings back to defaults, which is defined by the default settings file used when compiling Grbl. Often OEMs will build their Grbl firmwares with their machine-specific recommended settings. This provides users and OEMs a quick way to get back to square-one, if something went awry or if a user wants to start over.
-- `$RST=#` : Erases and zeros all G54-G59 work coordinate offsets and G28/30 positions stored in EEPROM. These are generally the values seen in the `$#` parameters printout. This provides an easy way to clear these without having to do it manually for each set with a `G20 L2/20` or `G28.1/30.1` command.
-- `$RST=*` : This clears and restores all of the EEPROM data used by Grbl. This includes `$$` settings, `$#` parameters, `$N` startup lines, and `$I` build info string. Note that this doesn't wipe the entire EEPROM, only the data areas Grbl uses. To do a complete wipe, please use the Arduino IDE's EEPROM clear example project.
-
-NOTE: Some OEMs may restrict some or all of these commands to prevent certain data they use from being wiped.
-
-#### `$SLP` - Enable Sleep Mode
-
-This command will place Grbl into a de-powered sleep state, shutting down the spindle, coolant, and stepper enable pins and block any commands. It may only be exited by a soft-reset or power-cycle. Once re-initialized, Grbl will automatically enter an ALARM state, because it's not sure where it is due to the steppers being disabled.
-
-This feature is useful if you need to automatically de-power everything at the end of a job by adding this command at the end of your g-code program, BUT, it is highly recommended that you add commands to first move your machine to a safe parking location prior to this sleep command. It also should be emphasized that you should have a reliable CNC machine that will disable everything when its supposed to, like your spindle. Grbl is not responsible for any damage it may cause. It's never a good idea to leave your machine unattended. So, use this command with the utmost caution!
-
-
-
-***
-
-## Other Resources:
-
diff --git a/doc/script/fit_nonlinear_spindle.py b/doc/script/fit_nonlinear_spindle.py
new file mode 100644
index 00000000..549a18c1
--- /dev/null
+++ b/doc/script/fit_nonlinear_spindle.py
@@ -0,0 +1,363 @@
+"""
+---------------------
+The MIT License (MIT)
+
+Copyright (c) 2017 Sungeun K. Jeon for Gnea Research LLC
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+---------------------
+"""
+
+
+"""
+This Python script produces a continuous piece-wise line fit of actual spindle speed over
+programmed speed/PWM, which must be measured and provided by the user. A plot of the data
+and line fit will be auto-generated and saved in the working directory as 'line_fit.png'.
+
+REQUIREMENTS:
+ - Python 2.7 or 3.x with SciPy, NumPy, and Matplotlib Python Libraries
+
+ - For the most people, the easiest way to run this script is on the free cloud service
+ https://repl.it/site/languages/python3. No account necessary. Unlimited runs. To use,
+ go to the website and start the Python REPL. Copy and paste this script into the
+ browser editor. Click the 'Add New File' icon on the upper left side. This is very
+ important. It places the REPL in multiple file mode and will enable viewing the plot.
+ Click the 'Run' icon. The solution will be presented in the console on the right side,
+ and the data plot will appear as a tab called 'line_fit.png'. You can edit the script
+ directly in the browser and re-run the script as many times as you need. A free
+ account is only necessary if you want to save files on their servers.
+
+ - For offline Python installs, most Mac and Linux computers have Python pre-installed
+ with the required libraries. If not, a quick google search will show you how to
+ install them. For Windows, Python installations are bit more difficult. Anaconda and
+ Pyzo seem to work well.
+
+USAGE:
+ - First, make sure you are using the stock build of Grbl for the 328p processor. Most
+ importantly, the SPINDLE_PWM_MAX_VALUE and SPINDLE_PWM_MIN_VALUE should be unaltered
+ from defaults, otherwise change them back to 255.0 and 1.0 respectively for this test.
+
+ - Next, program the max and min rpm Grbl settings to '$30=255' and '$31=1'. This sets
+ the internal PWM values equal to 'S' spindle speed for the standard Grbl build.
+
+ - Check if your spindle does not turn on at very low voltages by setting 'S' spindle
+ speed to 'S1'. If it does not turn on or turns at a non-useful rpm, increase 'S' by
+ one until it does. Write down this 'S' value for later. You'll start the rpm data
+ collection from this point onward and will need to update the SPINDLE_PWM_MIN_VALUE
+ in cpu_map.h afterwards.
+
+ - Collect actual spindle speed with a tachometer or similar means over a range of 'S'
+ and PWM values. Start by setting the spindle 'S' speed to the minimum useful 'S' from
+ the last step and measure and record actual spindle rpm. Next, increase 'S' spindle
+ speed over equally sized intervals and repeat the measurement. Increments of 20 rpm
+ should be more than enough, but decrease increment size, if highly nonlinear. Complete
+ the data collection the 'S' spindle speed equal to '$30' max rpm, or at the max useful
+ rpm, and record the actual rpm output. Make sure to collect rpm data all the way
+ throughout useful output rpm. The actual operating range within this model may be set
+ later within Grbl with the '$30' and '$31' settings.
+
+ - In some cases, spindle PWM output can have discontinuities or not have a useful rpm
+ in certain ranges. For example, a known controller board has the spindle rpm drop
+ completely at voltages above ~4.5V. If you have discontinuities like this at the low
+ or high range of rpm, simply trim them from the data set. Don't include them. For
+ Grbl to compensate, you'll need to alter the SPINDLE_PWM_MIN_VALUE and/or
+ SPINDLE_PWM_MAX_VALUE in cpu_map.h to where your data set ends. This script will
+ indicate if you need to do that in the solution output.
+
+ - Keep in mind that spindles without control electronics can slow down drastically when
+ cutting and under load. How much it slows down is dependent on a lot of factors, such
+ as feed rate, chip load, cutter diameter, flutes, cutter type, lubricant/coolant,
+ material being cut, etc. Even spindles with controllers can still slow down if the
+ load is higher than the max current the controller can provide. It's recommended to
+ frequently re-check and measure actual spindle speed during a job. You can always use
+ spindle speed overrides to tweak it temporarily to the desired speed.
+
+ - Edit this script and enter the measured rpm values and their corresponding 'S' spindle
+ speed values in the data arrays below. Set the number of piecewise lines you would
+ like to use, from one to four lines. For most cases, four lines is perfectly fine.
+ In certain scenarios (laser engraving), this may significantly degrade performance and
+ should be reduced if possible.
+
+ - Run the Python script. Visually assess the line fit from the plot. It will not likely
+ to what you want on the first go. Dial things in by altering the line fit junction
+ points 'PWM_pointX' in this script to move where the piecewise line junctions are
+ located along the plot x-axis. It may be desired to tweak the junction points so the
+ model solution is more accurate in the region that the spindle typically running.
+ Re-run the script and tweak the junction points until you are satified with the model.
+
+ - Record the solution and enter the RPM_POINT and RPM_LINE values into config.h. Set the
+ number of piecewise lines used in this model in config.h. Also set the '$30' and '$31'
+ max and min rpm values to the solution values or in a range between them in Grbl '$'
+ settings. And finally, alter the SPINDLE_PWM_MIN_VALUE in cpu_map.h, if your spindle
+ needs to be above a certain voltage to produce a useful low rpm.
+
+ - Once the solution is entered. Recompile and flash Grbl. This solution model is only
+ valid for this particular set of data. If the machine is altered, you will need to
+ perform this experiment again and regenerate a new model here.
+
+OUTPUT:
+ The solver produces a set of values that define the piecewise fit and can be used by
+ Grbl to quickly and efficiently compute spindle PWM output voltage for a desired RPM.
+
+ The first two are the RPM_MAX ($30) and RPM_MIN ($31) Grbl settings. These must be
+ programmed into Grbl manually or setup in defaults.h for new systems. Altering these
+ values within Grbl after a piece-wise linear model is installed will not change alter
+ model. It will only alter the range of spindle speed rpm values Grbl output.
+
+ For example, if the solver produces an RPM_MAX of 9000 and Grbl is programmed with
+ $30=8000, S9000 may be programmed, but Grbl will only produce the output voltage to run
+ at 8000 rpm. In other words, Grbl will only output voltages the range between
+ max(RPM_MIN,$31) and min(RPM_MAX,$30).
+
+ The remaining values define the slopes and offsets of the line segments and the junction
+ points between line segments, like so for n_pieces=3:
+
+ PWM_output = RPM_LINE_A1 * rpm - RPM_LINE_B1 [ RPM_MIN < rpm < RPM_POINT12 ]
+ PWM_output = RPM_LINE_A2 * rpm - RPM_LINE_B2 [ RPM_POINT12 < rpm < RPM_POINT23 ]
+ PWM_output = RPM_LINE_A3 * rpm - RPM_LINE_B3 [ RPM_POINT23 < rpm < RPM_MAX ]
+
+ NOTE: The script solves in terms of PWM but the final equations and values are expressed
+ in terms of rpm in the form 'PWM = a*rpm - b'.
+
+"""
+
+from scipy import optimize
+import numpy as np
+
+# ----------------------------------------------------------------------------------------
+# Configure spindle PWM line fit solver
+
+n_pieces = 4 # Number of line segments used for data fit. Only 1 to 4 line segments supported.
+
+# Programmed 'S' spindle speed values. Must start with minimum useful PWM or 'S' programmed
+# value and end with the maximum useful PWM or 'S' programmed value. Order of the array must
+# be synced with the RPM_measured array below.
+# NOTE: ** DO NOT USE DATA FROM AN EXISTING PIECEWISE LINE FIT. USE DEFAULT GRBL MODEL ONLY. **
+PWM_set = np.array([2,18,36,55,73,91,109,127,146,164,182,200,218,237,254], dtype=float)
+
+# Actual RPM measured at the spindle. Must be in the ascending value and equal in length
+# as the PWM_set array. Must include the min and max measured rpm output in the first and
+# last array entries, respectively.
+RPM_measured = np.array([213.,5420,7145,8282,9165,9765,10100,10500,10700,10900,11100,11250,11400,11550,11650], dtype=float)
+
+# Configure line fit points by 'S' programmed rpm or PWM value. Values must be between
+# PWM_max and PWM_min. Typically, alter these values to space the points evenly between
+# max and min PWM range. However, they may be tweaked to maximize accuracy in the places
+# you normally operate for highly nonlinear curves. Plot to visually assess how well the
+# solution fits the data.
+PWM_point1 = 20.0 # (S) Point between segments 0 and 1. Used when n_pieces >= 2.
+PWM_point2 = 80.0 # (S) Point between segments 1 and 2. Used when n_pieces >= 3.
+PWM_point3 = 150.0 # (S) Point between segments 2 and 3. Used when n_pieces = 4.
+
+# ----------------------------------------------------------------------------------------
+
+# Advanced settings
+
+# The optimizer requires an initial guess of the solution. Change value if solution fails.
+slope_i = 100.0; # > 0.0
+
+PWM_max = max(PWM_set) # Maximum PWM set in measured range
+PWM_min = min(PWM_set) # Minimum PWM set in measured range
+plot_figure = True # Set to False, if matplotlib is not available.
+
+# ----------------------------------------------------------------------------------------
+# DO NOT ALTER ANYTHING BELOW.
+
+def piecewise_linear_1(x,b,k1):
+ return np.piecewise(x, [(x>=PWM_min)&(x<=PWM_max)], [lambda x:k1*(x-PWM_min)+b])
+
+def piecewise_linear_2(x,b,k1,k2):
+ c = [b,
+ b+k1*(PWM_point1-PWM_min)]
+ funcs = [lambda x:k1*(x-PWM_min)+c[0],
+ lambda x:k2*(x-PWM_point1)+c[1]]
+ conds = [(x=PWM_min),
+ (x<=PWM_max)&(x>=PWM_point1)]
+ return np.piecewise(x, conds, funcs)
+
+def piecewise_linear_3(x,b,k1,k2,k3):
+ c = [b,
+ b+k1*(PWM_point1-PWM_min),
+ b+k1*(PWM_point1-PWM_min)+k2*(PWM_point2-PWM_point1)]
+ funcs = [lambda x:k1*(x-PWM_min)+c[0],
+ lambda x:k2*(x-PWM_point1)+c[1],
+ lambda x:k3*(x-PWM_point2)+c[2]]
+ conds = [(x=PWM_min),
+ (x=PWM_point1),
+ (x<=PWM_max)&(x>=PWM_point2)]
+ return np.piecewise(x, conds, funcs)
+
+def piecewise_linear_4(x,b,k1,k2,k3,k4):
+ c = [b,
+ b+k1*(PWM_point1-PWM_min),
+ b+k1*(PWM_point1-PWM_min)+k2*(PWM_point2-PWM_point1),
+ b+k1*(PWM_point1-PWM_min)+k2*(PWM_point2-PWM_point1)+k3*(PWM_point3-PWM_point2)]
+ funcs = [lambda x:k1*(x-PWM_min)+c[0],
+ lambda x:k2*(x-PWM_point1)+c[1],
+ lambda x:k3*(x-PWM_point2)+c[2],
+ lambda x:k4*(x-PWM_point3)+c[3]]
+ conds = [(x=PWM_min),
+ (x=PWM_point1),
+ (x=PWM_point2),
+ (x<=PWM_max)&(x>=PWM_point3)]
+ return np.piecewise(x, conds, funcs)
+
+# ----------------------------------------------------------------------------------------
+
+print("\nCONFIG:")
+print(" N_pieces: %i" % n_pieces)
+print(" PWM_min: %.1f" % PWM_min)
+print(" PWM_max: %.1f" % PWM_max)
+if n_pieces > 1:
+ print(" PWM_point1: %.1f" % PWM_point1)
+if n_pieces > 2:
+ print(" PWM_point2: %.1f" % PWM_point2)
+if n_pieces > 3:
+ print(" PWM_point3: %.1f" % PWM_point3)
+print(" N_data: %i" % len(RPM_measured))
+print(" PWM_set: ", PWM_set)
+print(" RPM_measured: ", RPM_measured)
+
+if n_pieces == 1:
+ piece_func = piecewise_linear_1
+ p_initial = [RPM_measured[0],slope_i]
+
+ p , e = optimize.curve_fit(piece_func, PWM_set, RPM_measured, p0=p_initial)
+ a = [p[1]]
+ b = [ p[0]-p[1]*PWM_min]
+ rpm = [ p[0],
+ p[0]+p[1]*(PWM_point1-PWM_min)]
+
+elif n_pieces == 2:
+ piece_func = piecewise_linear_2
+ p_initial = [RPM_measured[0],slope_i,slope_i]
+
+ p , e = optimize.curve_fit(piece_func, PWM_set, RPM_measured, p0=p_initial)
+ a = [p[1],p[2]]
+ b = [ p[0]-p[1]*PWM_min,
+ p[0]+p[1]*(PWM_point1-PWM_min)-p[2]*PWM_point1]
+ rpm = [ p[0],
+ p[0]+p[1]*(PWM_point1-PWM_min),
+ p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_max-PWM_point1)]
+
+elif n_pieces == 3:
+ piece_func = piecewise_linear_3
+ p_initial = [RPM_measured[0],slope_i,slope_i,slope_i]
+
+ p , e = optimize.curve_fit(piece_func, PWM_set, RPM_measured, p0=p_initial)
+ a = [p[1],p[2],p[3]]
+ b = [ p[0]-p[1]*PWM_min,
+ p[0]+p[1]*(PWM_point1-PWM_min)-p[2]*PWM_point1,
+ p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)-p[3]*PWM_point2]
+ rpm = [ p[0],
+ p[0]+p[1]*(PWM_point1-PWM_min),
+ p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1),
+ p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)+p[3]*(PWM_max-PWM_point2) ]
+
+elif n_pieces == 4:
+ piece_func = piecewise_linear_4
+ p_initial = [RPM_measured[0],slope_i,slope_i,slope_i,slope_i]
+
+ p , e = optimize.curve_fit(piece_func, PWM_set, RPM_measured, p0=p_initial)
+ a = [p[1],p[2],p[3],p[4]]
+ b = [ p[0]-p[1]*PWM_min,
+ p[0]+p[1]*(PWM_point1-PWM_min)-p[2]*PWM_point1,
+ p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)-p[3]*PWM_point2,
+ p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)+p[3]*(PWM_point3-PWM_point2)-p[4]*PWM_point3 ]
+ rpm = [ p[0],
+ p[0]+p[1]*(PWM_point1-PWM_min),
+ p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1),
+ p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)+p[3]*(PWM_point3-PWM_point2),
+ p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)+p[3]*(PWM_point3-PWM_point2)+p[4]*(PWM_max-PWM_point3) ]
+
+else :
+ print("ERROR: Unsupported number of pieces. Check and alter n_pieces")
+ quit()
+
+print("\nSOLUTION:\n\n[Update these #define values and uncomment]\n[ENABLE_PIECEWISE_LINEAR_SPINDLE in config.h.]")
+print("#define N_PIECES %.0f" % n_pieces)
+print("#define RPM_MAX %.1f" % rpm[-1])
+print("#define RPM_MIN %.1f" % rpm[0])
+
+if n_pieces > 1:
+ print("#define RPM_POINT12 %.1f" % rpm[1])
+if n_pieces > 2:
+ print("#define RPM_POINT23 %.1f" %rpm[2])
+if n_pieces > 3:
+ print("#define RPM_POINT34 %.1f" %rpm[3])
+
+print("#define RPM_LINE_A1 %.6e" % (1./a[0]))
+print("#define RPM_LINE_B1 %.6e" % (b[0]/a[0]))
+if n_pieces > 1:
+ print("#define RPM_LINE_A2 %.6e" % (1./a[1]))
+ print("#define RPM_LINE_B2 %.6e" % (b[1]/a[1]))
+if n_pieces > 2:
+ print("#define RPM_LINE_A3 %.6e" % (1./a[2]))
+ print("#define RPM_LINE_B3 %.6e" % (b[2]/a[2]))
+if n_pieces > 3:
+ print("#define RPM_LINE_A4 %.6e" % (1./a[3]))
+ print("#define RPM_LINE_B4 %.6e" % (b[3]/a[3]))
+
+print("\n[To operate over full model range, manually write these]")
+print("['$' settings or alter values in defaults.h. Grbl will]")
+print("[operate between min($30,RPM_MAX) and max($31,RPM_MIN)]")
+print("$30=%.1f (rpm max)" % rpm[-1])
+print("$31=%.1f (rpm min)" % rpm[0])
+
+if (PWM_min > 1)|(PWM_max<255):
+ print("\n[Update the following #define values in cpu_map.h]")
+ if (PWM_min >1) :
+ print("#define SPINDLE_PWM_MIN_VALUE %.0f" % PWM_min)
+ if PWM_max <255:
+ print("#define SPINDLE_PWM_MAX_VALUE %.0f" % PWM_max)
+else:
+ print("\n[No cpu_map.h changes required.]")
+print("\n")
+
+test_val = (1./a[0])*rpm[0] - (b[0]/a[0])
+if test_val < 0.0 :
+ print("ERROR: Solution is negative at RPM_MIN. Adjust junction points or increase n_pieces.\n")
+
+if plot_figure:
+ import matplotlib
+ matplotlib.use("Agg")
+ import matplotlib.pyplot as plt
+
+ fig = plt.figure()
+ ax = fig.add_subplot(111)
+ xd = np.linspace(PWM_min, PWM_max, 10000)
+ ax.plot(PWM_set, RPM_measured, "o")
+ ax.plot(xd, piece_func(xd, *p),'g')
+ plt.xlabel("Programmed PWM")
+ plt.ylabel("Measured RPM")
+
+ # Check solution by plotting in terms of rpm.
+# x = np.linspace(rpm[0], rpm[1], 10000)
+# ax.plot((1./a[0])*x-(b[0]/a[0]),x,'r:')
+# if n_pieces > 1:
+# x = np.linspace(rpm[1], rpm[2], 10000)
+# ax.plot((1./a[1])*x-(b[1]/a[1]),x,'r:')
+# if n_pieces > 2:
+# x = np.linspace(rpm[2], rpm[3], 10000)
+# ax.plot((1./a[2])*x-(b[2]/a[2]),x,'r:')
+# if n_pieces > 3:
+# x = np.linspace(rpm[3], rpm[-1], 10000)
+# ax.plot((1./a[3])*x-(b[3]/a[3]),x,'r:')
+
+ fig.savefig("line_fit.png")
diff --git a/doc/script/stream.py b/doc/script/stream.py
index d3857002..4a637ab9 100755
--- a/doc/script/stream.py
+++ b/doc/script/stream.py
@@ -11,16 +11,19 @@
buffer layer to prevent buffer starvation.
CHANGELOG:
+- 20170531: Status report feedback at 1.0 second intervals.
+ Configurable baudrate and report intervals. Bug fixes.
+- 20161212: Added push message feedback for simple streaming
- 20140714: Updated baud rate to 115200. Added a settings
write mode via simple streaming method. MIT-licensed.
TODO:
-- Add runtime command capabilities
+- Add realtime control commands during streaming.
---------------------
The MIT License (MIT)
-Copyright (c) 2012-2014 Sungeun K. Jeon
+Copyright (c) 2012-2017 Sungeun K. Jeon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -47,9 +50,14 @@
import time
import sys
import argparse
-# import threading
+import threading
RX_BUFFER_SIZE = 128
+BAUD_RATE = 115200
+ENABLE_STATUS_REPORTS = True
+REPORT_INTERVAL = 1.0 # seconds
+
+is_run = True # Controls query timer
# Define command line argument interface
parser = argparse.ArgumentParser(description='Stream g-code file to grbl. (pySerial and argparse libraries required)')
@@ -61,33 +69,63 @@
help='suppress output text')
parser.add_argument('-s','--settings',action='store_true', default=False,
help='settings write mode')
+parser.add_argument('-c','--check',action='store_true', default=False,
+ help='stream in check mode')
args = parser.parse_args()
# Periodic timer to query for status reports
# TODO: Need to track down why this doesn't restart consistently before a release.
-# def periodic():
-# s.write('?')
-# t = threading.Timer(0.1, periodic) # In seconds
-# t.start()
+def send_status_query():
+ s.write('?')
+
+def periodic_timer() :
+ while is_run:
+ send_status_query()
+ time.sleep(REPORT_INTERVAL)
+
# Initialize
-s = serial.Serial(args.device_file,115200)
+s = serial.Serial(args.device_file,BAUD_RATE)
f = args.gcode_file
verbose = True
if args.quiet : verbose = False
settings_mode = False
if args.settings : settings_mode = True
+check_mode = False
+if args.check : check_mode = True
# Wake up grbl
-print "Initializing grbl..."
+print "Initializing Grbl..."
s.write("\r\n\r\n")
# Wait for grbl to initialize and flush startup text in serial input
time.sleep(2)
s.flushInput()
+if check_mode :
+ print "Enabling Grbl Check-Mode: SND: [$C]",
+ s.write("$C\n")
+ while 1:
+ grbl_out = s.readline().strip() # Wait for grbl response with carriage return
+ if grbl_out.find('error') >= 0 :
+ print "REC:",grbl_out
+ print " Failed to set Grbl check-mode. Aborting..."
+ quit()
+ elif grbl_out.find('ok') >= 0 :
+ if verbose: print 'REC:',grbl_out
+ break
+
+start_time = time.time();
+
+# Start status report periodic timer
+if ENABLE_STATUS_REPORTS :
+ timerThread = threading.Thread(target=periodic_timer)
+ timerThread.daemon = True
+ timerThread.start()
+
# Stream g-code to grbl
l_count = 0
+error_count = 0
if settings_mode:
# Send settings file via simple call-response streaming method. Settings must be streamed
# in this manner since the EEPROM accessing cycles shut-off the serial interrupt.
@@ -96,10 +134,19 @@
l_count += 1 # Iterate line counter
# l_block = re.sub('\s|\(.*?\)','',line).upper() # Strip comments/spaces/new line and capitalize
l_block = line.strip() # Strip all EOL characters for consistency
- if verbose: print 'SND: ' + str(l_count) + ':' + l_block,
+ if verbose: print "SND>"+str(l_count)+": \"" + l_block + "\""
s.write(l_block + '\n') # Send g-code block to grbl
- grbl_out = s.readline().strip() # Wait for grbl response with carriage return
- if verbose: print 'REC:',grbl_out
+ while 1:
+ grbl_out = s.readline().strip() # Wait for grbl response with carriage return
+ if grbl_out.find('ok') >= 0 :
+ if verbose: print " REC<"+str(l_count)+": \""+grbl_out+"\""
+ break
+ elif grbl_out.find('error') >= 0 :
+ if verbose: print " REC<"+str(l_count)+": \""+grbl_out+"\""
+ error_count += 1
+ break
+ else:
+ print " MSG: \""+grbl_out+"\""
else:
# Send g-code program via a more agressive streaming protocol that forces characters into
# Grbl's serial read buffer to ensure Grbl has immediate access to the next g-code command
@@ -108,31 +155,48 @@
# responses, such that we never overflow Grbl's serial read buffer.
g_count = 0
c_line = []
- # periodic() # Start status report periodic timer
for line in f:
l_count += 1 # Iterate line counter
- # l_block = re.sub('\s|\(.*?\)','',line).upper() # Strip comments/spaces/new line and capitalize
- l_block = line.strip()
+ l_block = re.sub('\s|\(.*?\)','',line).upper() # Strip comments/spaces/new line and capitalize
+ # l_block = line.strip()
c_line.append(len(l_block)+1) # Track number of characters in grbl serial read buffer
grbl_out = ''
while sum(c_line) >= RX_BUFFER_SIZE-1 | s.inWaiting() :
out_temp = s.readline().strip() # Wait for grbl response
if out_temp.find('ok') < 0 and out_temp.find('error') < 0 :
- print " Debug: ",out_temp # Debug response
+ print " MSG: \""+out_temp+"\"" # Debug response
else :
- grbl_out += out_temp;
+ if out_temp.find('error') >= 0 : error_count += 1
g_count += 1 # Iterate g-code counter
- grbl_out += str(g_count); # Add line finished indicator
+ if verbose: print " REC<"+str(g_count)+": \""+out_temp+"\""
del c_line[0] # Delete the block character count corresponding to the last 'ok'
- if verbose: print "SND: " + str(l_count) + " : " + l_block,
s.write(l_block + '\n') # Send g-code block to grbl
- if verbose : print "BUF:",str(sum(c_line)),"REC:",grbl_out
+ if verbose: print "SND>"+str(l_count)+": \"" + l_block + "\""
+ # Wait until all responses have been received.
+ while l_count > g_count :
+ out_temp = s.readline().strip() # Wait for grbl response
+ if out_temp.find('ok') < 0 and out_temp.find('error') < 0 :
+ print " MSG: \""+out_temp+"\"" # Debug response
+ else :
+ if out_temp.find('error') >= 0 : error_count += 1
+ g_count += 1 # Iterate g-code counter
+ del c_line[0] # Delete the block character count corresponding to the last 'ok'
+ if verbose: print " REC<"+str(g_count)+": \""+out_temp + "\""
# Wait for user input after streaming is completed
-print "G-code streaming finished!\n"
-print "WARNING: Wait until grbl completes buffered g-code blocks before exiting."
-raw_input(" Press to exit and disable grbl.")
+print "\nG-code streaming finished!"
+end_time = time.time();
+is_run = False;
+print " Time elapsed: ",end_time-start_time,"\n"
+if check_mode :
+ if error_count > 0 :
+ print "CHECK FAILED:",error_count,"errors found! See output for details.\n"
+ else :
+ print "CHECK PASSED: No errors found in g-code program.\n"
+else :
+ print "WARNING: Wait until Grbl completes buffered g-code blocks before exiting."
+ raw_input(" Press to exit and disable Grbl.")
# Close file and serial port
f.close()
-s.close()
\ No newline at end of file
+s.close()
diff --git a/grbl/config.h b/grbl/config.h
index 04b9f1ab..9500f1e9 100644
--- a/grbl/config.h
+++ b/grbl/config.h
@@ -34,8 +34,17 @@
// NOTE: OEMs can avoid the need to maintain/update the defaults.h and cpu_map.h files and use only
// one configuration file by placing their specific defaults and pin map at the bottom of this file.
// If doing so, simply comment out these two defines and see instructions below.
-#define DEFAULTS_GENERIC
+//#define DEFAULTS_GENERIC
+#define DEFAULT_CNC3020
+#ifdef WIN32
+#define CPU_MAP_WIN32
+#endif
+#ifdef AVRTARGET
#define CPU_MAP_ATMEGA328P // Arduino Uno CPU
+#endif
+#ifdef STM32F103C8
+#define CPU_MAP_STM32F103
+#endif
// Serial baud rate
// #define BAUD_RATE 230400
@@ -251,7 +260,7 @@
#define DEFAULT_SPINDLE_SPEED_OVERRIDE 100 // 100%. Don't change this value.
#define MAX_SPINDLE_SPEED_OVERRIDE 200 // Percent of programmed spindle speed (100-255). Usually 200%.
-#define MIN_SPINDLE_SPEED_OVERRIDE 50 // Percent of programmed spindle speed (1-100). Usually 50%.
+#define MIN_SPINDLE_SPEED_OVERRIDE 10 // Percent of programmed spindle speed (1-100). Usually 10%.
#define SPINDLE_OVERRIDE_COARSE_INCREMENT 10 // (1-99). Usually 10%.
#define SPINDLE_OVERRIDE_FINE_INCREMENT 1 // (1-99). Usually 1%.
@@ -287,22 +296,6 @@
#define REPORT_WCO_REFRESH_BUSY_COUNT 30 // (2-255)
#define REPORT_WCO_REFRESH_IDLE_COUNT 10 // (2-255) Must be less than or equal to the busy count
-// ----- COMPATIBILITY OPTIONS: ------
-// The following options enabled the old-style v0.9 Grbl interface.
-// WARNING: DO NOT USE these compatibility options unless there is a really good reason to. If you are
-// trying to use Grbl v1.1 with a GUI that supports a v0.9-style interface, it will still not likely work.
-// A few things have been added, like override and accessory data and a new sleep state. These things will
-// still likely require the GUI to be updated to handle these. In other words, IT WILL STILL NOT WORK!
-// IT'S HIGHLY RECOMMENDED FOR GUIs TO UPDATE TO THE NEW INTERFACE FOR v1.1. Don't try to make it
-// compatible with this old v0.9 style. It will be dropped in the near future. You have been warned.
-// NOTE: The compiled size of Grbl with these options enabled will exceed the flash limit of FTDI-based
-// Arduinos, like the Duemilanove and Nano. This will only fit on an Uno with the Optiboot bootloader.
-// #define USE_CLASSIC_GRBL_INTERFACE // Default disabled. Uncomment to enable.
-// #define REPORT_ALL_PIN_STATES // Default disabled. Uncomment to enable. Option obsolete in v1.1.
-// #define REPORT_REALTIME_RATE // Disabled by default. Uncomment to enable. Option obsolete in v1.1.
-// Enables minimal reporting feedback mode for GUIs, where human-readable strings are not as important.
-// -----------------------------------
-
// The temporal resolution of the acceleration management subsystem. A higher number gives smoother
// acceleration, particularly noticeable on machines that run at very high feedrates, but may negatively
// impact performance. The correct value for this parameter is machine dependent, so it's advised to
@@ -361,20 +354,28 @@
// and the voltage set by the minimum PWM for minimum rpm. This difference is 0.02V per PWM value. So, when
// minimum PWM is at 1, only 0.02 volts separate enabled and disabled. At PWM 5, this would be 0.1V. Keep
// in mind that you will begin to lose PWM resolution with increased minimum PWM values, since you have less
-// and less range over the total 256 PWM levels to signal different spindle speeds.
-// NOTE: Compute duty cycle at the minimum PWM by this equation: (% duty cycle)=(SPINDLE_MINIMUM_PWM/256)*100
-// #define SPINDLE_MINIMUM_PWM_VALUE 5 // Default disabled. Uncomment to enable. Must be greater than zero. Integer (1-255).
+// and less range over the total 255 PWM levels to signal different spindle speeds.
+// NOTE: Compute duty cycle at the minimum PWM by this equation: (% duty cycle)=(SPINDLE_PWM_MIN_VALUE/255)*100
+// #define SPINDLE_PWM_MIN_VALUE 5 // Default disabled. Uncomment to enable. Must be greater than zero. Integer (1-255).
// By default on a 328p(Uno), Grbl combines the variable spindle PWM and the enable into one pin to help
// preserve I/O pins. For certain setups, these may need to be separate pins. This configure option uses
// the spindle direction pin(D13) as a separate spindle enable pin along with spindle speed PWM on pin D11.
// NOTE: This configure option only works with VARIABLE_SPINDLE enabled and a 328p processor (Uno).
-// NOTE: With no direction pin, the spindle clockwise M4 g-code command will be removed. M3 and M5 still work.
+// NOTE: Without a direction pin, M4 will not have a pin output to indicate a difference with M3.
// NOTE: BEWARE! The Arduino bootloader toggles the D13 pin when it powers up. If you flash Grbl with
// a programmer (you can use a spare Arduino as "Arduino as ISP". Search the web on how to wire this.),
// this D13 LED toggling should go away. We haven't tested this though. Please report how it goes!
// #define USE_SPINDLE_DIR_AS_ENABLE_PIN // Default disabled. Uncomment to enable.
+// Alters the behavior of the spindle enable pin with the USE_SPINDLE_DIR_AS_ENABLE_PIN option . By default,
+// Grbl will not disable the enable pin if spindle speed is zero and M3/4 is active, but still sets the PWM
+// output to zero. This allows the users to know if the spindle is active and use it as an additional control
+// input. However, in some use cases, user may want the enable pin to disable with a zero spindle speed and
+// re-enable when spindle speed is greater than zero. This option does that.
+// NOTE: Requires USE_SPINDLE_DIR_AS_ENABLE_PIN to be enabled.
+// #define SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED // Default disabled. Uncomment to enable.
+
// With this enabled, Grbl sends back an echo of the line it has received, which has been pre-parsed (spaces
// removed, capitalized letters, no comments) and is to be immediately executed by Grbl. Echoes will not be
// sent upon a line buffer overflow, but should for all normal lines sent to Grbl. For example, if a user
@@ -390,7 +391,7 @@
// limits or angle between neighboring block line move directions. This is useful for machines that can't
// tolerate the tool dwelling for a split second, i.e. 3d printers or laser cutters. If used, this value
// should not be much greater than zero or to the minimum value necessary for the machine to work.
-#define MINIMUM_JUNCTION_SPEED 0.0 // (mm/min)
+#define MINIMUM_JUNCTION_SPEED 0.0f // (mm/min)
// Sets the minimum feed rate the planner will allow. Any value below it will be set to this minimum
// value. This also ensures that a planned motion always completes and accounts for any floating-point
@@ -467,8 +468,19 @@
// 115200 baud will take 5 msec to transmit a typical 55 character report. Worst case reports are
// around 90-100 characters. As long as the serial TX buffer doesn't get continually maxed, Grbl
// will continue operating efficiently. Size the TX buffer around the size of a worst-case report.
+#if !defined (STM32F103C8)
// #define RX_BUFFER_SIZE 128 // (1-254) Uncomment to override defaults in serial.h
// #define TX_BUFFER_SIZE 100 // (1-254)
+#endif
+
+// A simple software debouncing feature for hard limit switches. When enabled, the interrupt
+// monitoring the hard limit switch pins will enable the Arduino's watchdog timer to re-check
+// the limit pin state after a delay of about 32msec. This can help with CNC machines with
+// problematic false triggering of their hard limit switches, but it WILL NOT fix issues with
+// electrical interference on the signal cables from external sources. It's recommended to first
+// use shielded signal cables with their shielding connected to ground (old USB/computer cables
+// work well and are cheap to find) and wire in a low-pass circuit into each limit pin.
+// #define ENABLE_SOFTWARE_DEBOUNCE // Default disabled. Uncomment to enable.
// Configures the position after a probing cycle during Grbl's check mode. Disabled sets
// the position to the probe target, when enabled sets the position to the start position.
@@ -491,8 +503,8 @@
// uses the homing pull-off distance setting times the LOCATE_SCALAR to pull-off and re-engage
// the limit switch.
// NOTE: Both of these values must be greater than 1.0 to ensure proper function.
-// #define HOMING_AXIS_SEARCH_SCALAR 1.5 // Uncomment to override defaults in limits.c.
-// #define HOMING_AXIS_LOCATE_SCALAR 10.0 // Uncomment to override defaults in limits.c.
+// #define HOMING_AXIS_SEARCH_SCALAR 1.5f // Uncomment to override defaults in limits.c.
+// #define HOMING_AXIS_LOCATE_SCALAR 10.0f // Uncomment to override defaults in limits.c.
// Enable the '$RST=*', '$RST=$', and '$RST=#' eeprom restore commands. There are cases where
// these commands may be undesirable. Simply comment the desired macro to disable it.
@@ -564,18 +576,51 @@
// Configure options for the parking motion, if enabled.
#define PARKING_AXIS Z_AXIS // Define which axis that performs the parking motion
-#define PARKING_TARGET -5.0 // Parking axis target. In mm, as machine coordinate [-max_travel,0].
-#define PARKING_RATE 500.0 // Parking fast rate after pull-out in mm/min.
-#define PARKING_PULLOUT_RATE 100.0 // Pull-out/plunge slow feed rate in mm/min.
-#define PARKING_PULLOUT_INCREMENT 5.0 // Spindle pull-out and plunge distance in mm. Incremental distance.
+#define PARKING_TARGET -5.0f // Parking axis target. In mm, as machine coordinate [-max_travel,0].
+#define PARKING_RATE 500.0f // Parking fast rate after pull-out in mm/min.
+#define PARKING_PULLOUT_RATE 100.0f // Pull-out/plunge slow feed rate in mm/min.
+#define PARKING_PULLOUT_INCREMENT 5.0f // Spindle pull-out and plunge distance in mm. Incremental distance.
// Must be positive value or equal to zero.
+// Enables a special set of M-code commands that enables and disables the parking motion.
+// These are controlled by `M56`, `M56 P1`, or `M56 Px` to enable and `M56 P0` to disable.
+// The command is modal and will be set after a planner sync. Since it is g-code, it is
+// executed in sync with g-code commands. It is not a real-time command.
+// NOTE: PARKING_ENABLE is required. By default, M56 is active upon initialization. Use
+// DEACTIVATE_PARKING_UPON_INIT to set M56 P0 as the power-up default.
+// #define ENABLE_PARKING_OVERRIDE_CONTROL // Default disabled. Uncomment to enable
+// #define DEACTIVATE_PARKING_UPON_INIT // Default disabled. Uncomment to enable.
+
// This option will automatically disable the laser during a feed hold by invoking a spindle stop
// override immediately after coming to a stop. However, this also means that the laser still may
// be reenabled by disabling the spindle stop override, if needed. This is purely a safety feature
// to ensure the laser doesn't inadvertently remain powered while at a stop and cause a fire.
#define DISABLE_LASER_DURING_HOLD // Default enabled. Comment to disable.
+// Enables a piecewise linear model of the spindle PWM/speed output. Requires a solution by the
+// 'fit_nonlinear_spindle.py' script in the /doc/script folder of the repo. See file comments
+// on how to gather spindle data and run the script to generate a solution.
+// #define ENABLE_PIECEWISE_LINEAR_SPINDLE // Default disabled. Uncomment to enable.
+
+// N_PIECES, RPM_MAX, RPM_MIN, RPM_POINTxx, and RPM_LINE_XX constants are all set and given by
+// the 'fit_nonlinear_spindle.py' script solution. Used only when ENABLE_PIECEWISE_LINEAR_SPINDLE
+// is enabled. Make sure the constant values are exactly the same as the script solution.
+// NOTE: When N_PIECES < 4, unused RPM_LINE and RPM_POINT defines are not required and omitted.
+#define N_PIECES 4 // Integer (1-4). Number of piecewise lines used in script solution.
+#define RPM_MAX 11686.4 // Max RPM of model. $30 > RPM_MAX will be limited to RPM_MAX.
+#define RPM_MIN 202.5 // Min RPM of model. $31 < RPM_MIN will be limited to RPM_MIN.
+#define RPM_POINT12 6145.4 // Used N_PIECES >=2. Junction point between lines 1 and 2.
+#define RPM_POINT23 9627.8 // Used N_PIECES >=3. Junction point between lines 2 and 3.
+#define RPM_POINT34 10813.9 // Used N_PIECES = 4. Junction point between lines 3 and 4.
+#define RPM_LINE_A1 3.197101e-03 // Used N_PIECES >=1. A and B constants of line 1.
+#define RPM_LINE_B1 -3.526076e-1
+#define RPM_LINE_A2 1.722950e-2 // Used N_PIECES >=2. A and B constants of line 2.
+#define RPM_LINE_B2 8.588176e+01
+#define RPM_LINE_A3 5.901518e-02 // Used N_PIECES >=3. A and B constants of line 3.
+#define RPM_LINE_B3 4.881851e+02
+#define RPM_LINE_A4 1.203413e-01 // Used N_PIECES = 4. A and B constants of line 4.
+#define RPM_LINE_B4 1.151360e+03
+
/* ---------------------------------------------------------------------------------------
OEM Single File Configuration Option
diff --git a/grbl/coolant_control.c b/grbl/coolant_control.c
index 418cdac4..012be434 100644
--- a/grbl/coolant_control.c
+++ b/grbl/coolant_control.c
@@ -23,10 +23,26 @@
void coolant_init()
{
+#ifdef AVRTARGET
COOLANT_FLOOD_DDR |= (1 << COOLANT_FLOOD_BIT); // Configure as output pin
#ifdef ENABLE_M7
COOLANT_MIST_DDR |= (1 << COOLANT_MIST_BIT);
#endif
+#endif
+#ifdef STM32F103C8
+ GPIO_InitTypeDef GPIO_InitStructure;
+ RCC_APB2PeriphClockCmd(RCC_COOLANT_FLOOD_PORT, ENABLE);
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+ GPIO_InitStructure.GPIO_Pin = 1 << COOLANT_FLOOD_BIT;
+ GPIO_Init(COOLANT_FLOOD_PORT, &GPIO_InitStructure);
+
+ RCC_APB2PeriphClockCmd(RCC_COOLANT_MIST_PORT, ENABLE);
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+ GPIO_InitStructure.GPIO_Pin = 1 << COOLANT_MIST_BIT;
+ GPIO_Init(COOLANT_MIST_PORT, &GPIO_InitStructure);
+#endif
coolant_stop();
}
@@ -35,22 +51,48 @@ void coolant_init()
uint8_t coolant_get_state()
{
uint8_t cl_state = COOLANT_STATE_DISABLE;
+#if defined(AVRTARGET) || defined(STM32F103C8)
#ifdef INVERT_COOLANT_FLOOD_PIN
- if (bit_isfalse(COOLANT_FLOOD_PORT,(1 << COOLANT_FLOOD_BIT))) {
+ if (bit_isfalse(
+#ifdef AVRTARGET
+ COOLANT_FLOOD_PORT
+#else
+ GPIO_ReadOutputData(COOLANT_FLOOD_PORT)
+#endif
+ ,(1 << COOLANT_FLOOD_BIT))) {
#else
- if (bit_istrue(COOLANT_FLOOD_PORT,(1 << COOLANT_FLOOD_BIT))) {
+ if (bit_istrue(
+#ifdef AVRTARGET
+ COOLANT_FLOOD_PORT
+#else
+ GPIO_ReadOutputData(COOLANT_FLOOD_PORT)
+#endif
+ ,(1 << COOLANT_FLOOD_BIT))) {
#endif
cl_state |= COOLANT_STATE_FLOOD;
}
#ifdef ENABLE_M7
#ifdef INVERT_COOLANT_MIST_PIN
- if (bit_isfalse(COOLANT_MIST_PORT,(1 << COOLANT_MIST_BIT))) {
+ if (bit_isfalse(
+#ifdef AVRTARGET
+ COOLANT_MIST_PORT
+#else
+ GPIO_ReadOutputData(COOLANT_MIST_PORT)
+#endif
+ ,(1 << COOLANT_MIST_BIT))) {
#else
- if (bit_istrue(COOLANT_MIST_PORT,(1 << COOLANT_MIST_BIT))) {
+ if (bit_istrue(
+#ifdef AVRTARGET
+ COOLANT_MIST_PORT
+#else
+ GPIO_ReadOutputData(COOLANT_MIST_PORT)
+#endif
+ ,(1 << COOLANT_MIST_BIT))) {
#endif
cl_state |= COOLANT_STATE_MIST;
}
#endif
+#endif
return(cl_state);
}
@@ -59,18 +101,36 @@ uint8_t coolant_get_state()
// an interrupt-level. No report flag set, but only called by routines that don't need it.
void coolant_stop()
{
+#if defined(AVRTARGET) || defined(STM32F103C8)
#ifdef INVERT_COOLANT_FLOOD_PIN
+#ifdef AVRTARGET
COOLANT_FLOOD_PORT |= (1 << COOLANT_FLOOD_BIT);
+#else
+ GPIO_SetBits(COOLANT_FLOOD_PORT,1 << COOLANT_FLOOD_BIT);
+#endif
#else
- COOLANT_FLOOD_PORT &= ~(1 << COOLANT_FLOOD_BIT);
+#ifdef AVRTARGET
+ COOLANT_FLOOD_PORT &= ~(1 << COOLANT_FLOOD_BIT);
+#else
+ GPIO_ResetBits(COOLANT_FLOOD_PORT,1 << COOLANT_FLOOD_BIT);
+#endif
#endif
#ifdef ENABLE_M7
#ifdef INVERT_COOLANT_MIST_PIN
+#ifdef AVRTARGET
COOLANT_MIST_PORT |= (1 << COOLANT_MIST_BIT);
+#else
+ GPIO_SetBits(COOLANT_MIST_PORT, 1 << COOLANT_MIST_BIT);
+#endif
#else
- COOLANT_MIST_PORT &= ~(1 << COOLANT_MIST_BIT);
+#ifdef AVRTARGET
+ COOLANT_MIST_PORT &= ~(1 << COOLANT_MIST_BIT);
+#else
+ GPIO_ResetBits(COOLANT_MIST_PORT, 1 << COOLANT_MIST_BIT);
+#endif
#endif
#endif
+#endif
}
@@ -88,24 +148,41 @@ void coolant_set_state(uint8_t mode)
} else {
- if (mode & COOLANT_FLOOD_ENABLE) {
+#if defined(AVRTARGET) || defined(STM32F103C8)
+ if (mode & COOLANT_FLOOD_ENABLE) {
#ifdef INVERT_COOLANT_FLOOD_PIN
+#ifdef AVRTARGET
COOLANT_FLOOD_PORT &= ~(1 << COOLANT_FLOOD_BIT);
+#else
+ GPIO_ResetBits(COOLANT_FLOOD_PORT,1 << COOLANT_FLOOD_BIT);
+#endif
#else
- COOLANT_FLOOD_PORT |= (1 << COOLANT_FLOOD_BIT);
+#ifdef AVRTARGET
+ COOLANT_FLOOD_PORT |= (1 << COOLANT_FLOOD_BIT);
+#else
+ GPIO_SetBits(COOLANT_FLOOD_PORT,1 << COOLANT_FLOOD_BIT);
+#endif
#endif
}
#ifdef ENABLE_M7
if (mode & COOLANT_MIST_ENABLE) {
#ifdef INVERT_COOLANT_MIST_PIN
- COOLANT_MIST_PORT &= ~(1 << COOLANT_MIST_BIT);
+#ifdef AVRTARGET
+ COOLANT_MIST_PORT &= ~(1 << COOLANT_MIST_BIT);
+#else
+ GPIO_ResetBits(COOLANT_MIST_PORT, 1 << COOLANT_MIST_BIT);
+#endif
#else
- COOLANT_MIST_PORT |= (1 << COOLANT_MIST_BIT);
+#ifdef AVRTARGET
+ COOLANT_MIST_PORT |= (1 << COOLANT_MIST_BIT);
+#else
+ GPIO_SetBits(COOLANT_MIST_PORT, 1 << COOLANT_MIST_BIT);
+#endif
#endif
}
#endif
-
+#endif
}
sys.report_ovr_counter = 0; // Set to report change immediately
}
diff --git a/grbl/cpu_map.h b/grbl/cpu_map.h
index f2ce5309..e6dc6372 100644
--- a/grbl/cpu_map.h
+++ b/grbl/cpu_map.h
@@ -54,6 +54,9 @@
#define STEPPERS_DISABLE_PORT PORTB
#define STEPPERS_DISABLE_BIT 0 // Uno Digital Pin 8
#define STEPPERS_DISABLE_MASK (1<
#include
-
/* These EEPROM bits have different names on different devices. */
#ifndef EEPE
#define EEPE EEWE //!< EEPROM program/write enable.
@@ -36,6 +37,110 @@
/* Define to reduce code size. */
#define EEPROM_IGNORE_SELFPROG //!< Remove SPM flag polling.
+#endif
+#ifdef WIN32
+#include
+#include
+#endif
+#ifdef STM32F103C8
+#include
+#include "stm32eeprom.h"
+#include "settings.h"
+#endif
+#if defined(WIN32) || defined (STM32F103C8)
+unsigned char EE_Buffer[0x400];
+#endif
+#if defined(WIN32)
+#ifndef NOEEPROMSUPPORT
+void eeprom_flush()
+{
+ FILE *out = fopen("eeprom.bin", "wb");
+ fwrite(EE_Buffer, 1, 0x400, out);
+ fclose(out);
+}
+#endif
+void eeprom_init()
+{
+#ifndef NOEEPROMSUPPORT
+ FILE *in = fopen("eeprom.bin", "rb");
+ if (in != NULL)
+ {
+ fread(EE_Buffer, 1, 0x400, in);
+ fclose(in);
+ }
+ else
+ {
+ memset(EE_Buffer, 0xff, 0x400);
+ }
+#else
+ memset(EE_Buffer, 0x0, 0x400);
+#endif
+}
+#endif
+
+#ifdef STM32F103C8
+#ifndef NOEEPROMSUPPORT
+void eeprom_flush()
+{
+ uint32_t nAddress = EEPROM_START_ADDRESS;
+ uint16_t *pBuffer = (uint16_t *)EE_Buffer;
+ uint16_t nSize = PAGE_SIZE;
+
+ FLASH_Status FlashStatus = FLASH_COMPLETE;
+
+ /* Erase Page0 */
+ FlashStatus = FLASH_ErasePage(EEPROM_START_ADDRESS);
+
+ /* If erase operation was failed, a Flash error code is returned */
+ if (FlashStatus != FLASH_COMPLETE)
+ {
+ return;
+ }
+
+ while (nSize > 0)
+ {
+ if (*pBuffer != 0xffff)
+ {
+ FLASH_ProgramHalfWord(nAddress, *pBuffer++);
+ }
+ else
+ {
+ pBuffer++;
+ }
+ if (*pBuffer != 0xffff)
+ {
+ FLASH_ProgramHalfWord(nAddress + 2, *pBuffer++);
+ }
+ else
+ {
+ pBuffer++;
+ }
+ nSize -= 4;
+ nAddress += 4;
+ }
+}
+void eeprom_init()
+{
+ uint16_t VarIdx = 0;
+ uint8_t *pTmp = EE_Buffer;
+
+ for (VarIdx = 0; VarIdx < PAGE_SIZE; VarIdx++)
+ {
+ *pTmp++ = (*(__IO uint8_t*)(EEPROM_START_ADDRESS + VarIdx));
+ }
+
+ if (EE_Buffer[0] != SETTINGS_VERSION)
+ {
+ pTmp = EE_Buffer;
+
+ for (VarIdx = 0; VarIdx < PAGE_SIZE; VarIdx++)
+ {
+ *pTmp++ = 0xFF;
+ }
+ }
+}
+#endif
+#endif
/*! \brief Read byte from EEPROM.
*
@@ -48,10 +153,15 @@
*/
unsigned char eeprom_get_char( unsigned int addr )
{
+#ifdef AVRTARGET
do {} while( EECR & (1< MAX_TOOL_NUMBER) { FAIL(STATUS_GCODE_MAX_VALUE_EXCEEDED); }
+ gc_block.values.t = int_value;
+ break;
+ case 'X': word_bit = WORD_X; gc_block.values.xyz[X_AXIS] = value; axis_words |= (1< N_COORDINATE_SYSTEM) { FAIL(STATUS_GCODE_UNSUPPORTED_COORD_SYS); } // [Greater than N sys]
if (gc_block.values.l != 20) {
if (gc_block.values.l == 2) {
@@ -631,10 +644,9 @@ uint8_t gc_execute_line(char *line)
// [20. Motion modes ]:
if (gc_block.modal.motion == MOTION_MODE_NONE) {
- // [G80 Errors]: Axis word exist and are not used by a non-modal command.
- if ((axis_words) && (axis_command != AXIS_COMMAND_NON_MODAL)) {
- FAIL(STATUS_GCODE_AXIS_WORDS_EXIST); // [No axis words allowed]
- }
+ // [G80 Errors]: Axis word are programmed while G80 is active.
+ // NOTE: Even non-modal commands or TLO that use axis words will throw this strict error.
+ if (axis_words) { FAIL(STATUS_GCODE_AXIS_WORDS_EXIST); } // [No axis words allowed]
// Check remaining motion modes, if axis word are implicit (exist and not used by G10/28/30/92), or
// was explicitly commanded in the g-code block.
@@ -649,13 +661,14 @@ uint8_t gc_execute_line(char *line)
// the value must be positive. In inverse time mode, a positive value must be passed with each block.
} else {
// Check if feed rate is defined for the motion modes that require it.
- if (gc_block.values.f == 0.0) { FAIL(STATUS_GCODE_UNDEFINED_FEED_RATE); } // [Feed rate undefined]
+ if (gc_block.values.f == 0.0f) { FAIL(STATUS_GCODE_UNDEFINED_FEED_RATE); } // [Feed rate undefined]
switch (gc_block.modal.motion) {
case MOTION_MODE_LINEAR:
// [G1 Errors]: Feed rate undefined. Axis letter not configured or without real value.
// Axis words are optional. If missing, set axis command flag to ignore execution.
if (!axis_words) { axis_command = AXIS_COMMAND_NONE; }
+
break;
case MOTION_MODE_CW_ARC:
gc_parser_flags |= GC_PARSER_ARC_IS_CLOCKWISE; // No break intentional.
@@ -731,12 +744,12 @@ uint8_t gc_execute_line(char *line)
// First, use h_x2_div_d to compute 4*h^2 to check if it is negative or r is smaller
// than d. If so, the sqrt of a negative number is complex and error out.
- float h_x2_div_d = 4.0 * gc_block.values.r*gc_block.values.r - x*x - y*y;
+ float h_x2_div_d = 4.0f * gc_block.values.r*gc_block.values.r - x*x - y*y;
if (h_x2_div_d < 0) { FAIL(STATUS_GCODE_ARC_RADIUS_ERROR); } // [Arc radius error]
// Finish computing h_x2_div_d.
- h_x2_div_d = -sqrt(h_x2_div_d)/hypot_f(x,y); // == -(h * 2 / d)
+ h_x2_div_d = -sqrtf(h_x2_div_d)/hypot_f(x,y); // == -(h * 2 / d)
// Invert the sign of h_x2_div_d if the circle is counter clockwise (see sketch below)
if (gc_block.modal.motion == MOTION_MODE_CCW_ARC) { h_x2_div_d = -h_x2_div_d; }
@@ -764,8 +777,8 @@ uint8_t gc_execute_line(char *line)
gc_block.values.r = -gc_block.values.r; // Finished with r. Set to positive for mc_arc
}
// Complete the operation by calculating the actual center of the arc
- gc_block.values.ijk[axis_0] = 0.5*(x-(y*h_x2_div_d));
- gc_block.values.ijk[axis_1] = 0.5*(y+(x*h_x2_div_d));
+ gc_block.values.ijk[axis_0] = 0.5f*(x-(y*h_x2_div_d));
+ gc_block.values.ijk[axis_1] = 0.5f*(y+(x*h_x2_div_d));
} else { // Arc Center Format Offset Mode
if (!(ijk_words & (bit(axis_0)|bit(axis_1)))) { FAIL(STATUS_GCODE_NO_OFFSETS_IN_PLANE); } // [No offsets in plane]
@@ -787,18 +800,18 @@ uint8_t gc_execute_line(char *line)
gc_block.values.r = hypot_f(gc_block.values.ijk[axis_0], gc_block.values.ijk[axis_1]);
// Compute difference between current location and target radii for final error-checks.
- float delta_r = fabs(target_r-gc_block.values.r);
- if (delta_r > 0.005) {
- if (delta_r > 0.5) { FAIL(STATUS_GCODE_INVALID_TARGET); } // [Arc definition error] > 0.5mm
- if (delta_r > (0.001*gc_block.values.r)) { FAIL(STATUS_GCODE_INVALID_TARGET); } // [Arc definition error] > 0.005mm AND 0.1% radius
+ float delta_r = fabsf(target_r-gc_block.values.r);
+ if (delta_r > 0.005f) {
+ if (delta_r > 0.5f) { FAIL(STATUS_GCODE_INVALID_TARGET); } // [Arc definition error] > 0.5mm
+ if (delta_r > (0.001f*gc_block.values.r)) { FAIL(STATUS_GCODE_INVALID_TARGET); } // [Arc definition error] > 0.005mm AND 0.1% radius
}
}
break;
case MOTION_MODE_PROBE_TOWARD_NO_ERROR: case MOTION_MODE_PROBE_AWAY_NO_ERROR:
- gc_parser_flags |= GC_PARSER_PROBE_IS_NO_ERROR; // No break intentional.
+ gc_parser_flags |= GC_PARSER_PROBE_IS_NO_ERROR; // No break intentional.
case MOTION_MODE_PROBE_TOWARD: case MOTION_MODE_PROBE_AWAY:
- if ((gc_block.modal.motion == MOTION_MODE_PROBE_AWAY) ||
- (gc_block.modal.motion == MOTION_MODE_PROBE_AWAY_NO_ERROR)) { gc_parser_flags |= GC_PARSER_PROBE_IS_AWAY; }
+ if ((gc_block.modal.motion == MOTION_MODE_PROBE_AWAY) ||
+ (gc_block.modal.motion == MOTION_MODE_PROBE_AWAY_NO_ERROR)) { gc_parser_flags |= GC_PARSER_PROBE_IS_AWAY; }
// [G38 Errors]: Target is same current. No axis words. Cutter compensation is enabled. Feed rate
// is undefined. Probe is triggered. NOTE: Probe check moved to probe cycle. Instead of returning
// an error, it issues an alarm to prevent further motion to the probe. It's also done there to
@@ -815,10 +828,10 @@ uint8_t gc_execute_line(char *line)
// [0. Non-specific error-checks]: Complete unused value words check, i.e. IJK used when in arc
// radius mode, or axis words that aren't used in the block.
if (gc_parser_flags & GC_PARSER_JOG_MOTION) {
- // Jogging only uses the F feed rate and XYZ value words. N is valid, but S and T are invalid.
- bit_false(value_words,(bit(WORD_N)|bit(WORD_F)));
+ // Jogging only uses the F feed rate and XYZ value words. N is valid, but S and T are invalid.
+ bit_false(value_words, (bit(WORD_N) | bit(WORD_F)));
} else {
- bit_false(value_words,(bit(WORD_N)|bit(WORD_F)|bit(WORD_S)|bit(WORD_T))); // Remove single-meaning value words.
+ bit_false(value_words, (bit(WORD_N) | bit(WORD_F) | bit(WORD_S) | bit(WORD_T))); // Remove single-meaning value words.
}
if (axis_command) { bit_false(value_words,(bit(WORD_X)|bit(WORD_Y)|bit(WORD_Z))); } // Remove axis words.
if (value_words) { FAIL(STATUS_GCODE_UNUSED_WORDS); } // [Unused words]
@@ -834,58 +847,56 @@ uint8_t gc_execute_line(char *line)
plan_line_data_t *pl_data = &plan_data;
memset(pl_data,0,sizeof(plan_line_data_t)); // Zero pl_data struct
- // Intercept jog commands and complete error checking for valid jog commands and execute.
- // NOTE: G-code parser state is not updated, except the position to ensure sequential jog
- // targets are computed correctly. The final parser position after a jog is updated in
- // protocol_execute_realtime() when jogging completes or is canceled.
+ // Intercept jog commands and complete error checking for valid jog commands and execute.
+ // NOTE: G-code parser state is not updated, except the position to ensure sequential jog
+ // targets are computed correctly. The final parser position after a jog is updated in
+ // protocol_execute_realtime() when jogging completes or is canceled.
if (gc_parser_flags & GC_PARSER_JOG_MOTION) {
- // Only distance and unit modal commands and G53 absolute override command are allowed.
- // NOTE: Feed rate word and axis word checks have already been performed in STEP 3.
- if (command_words & ~(bit(MODAL_GROUP_G3) | bit(MODAL_GROUP_G6 | bit(MODAL_GROUP_G0))) ) { FAIL(STATUS_INVALID_JOG_COMMAND) };
- if (!(gc_block.non_modal_command == NON_MODAL_ABSOLUTE_OVERRIDE || gc_block.non_modal_command == NON_MODAL_NO_ACTION)) { FAIL(STATUS_INVALID_JOG_COMMAND); }
-
- // Initialize planner data to current spindle and coolant modal state.
- pl_data->spindle_speed = gc_state.spindle_speed;
- plan_data.condition = (gc_state.modal.spindle | gc_state.modal.coolant);
-
- uint8_t status = jog_execute(&plan_data, &gc_block);
- if (status == STATUS_OK) { memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_block.values.xyz)); }
- return(status);
+ // Only distance and unit modal commands and G53 absolute override command are allowed.
+ // NOTE: Feed rate word and axis word checks have already been performed in STEP 3.
+ if (command_words & ~(bit(MODAL_GROUP_G3) | bit(MODAL_GROUP_G6 | bit(MODAL_GROUP_G0)))) { FAIL(STATUS_INVALID_JOG_COMMAND) };
+ if (!(gc_block.non_modal_command == NON_MODAL_ABSOLUTE_OVERRIDE || gc_block.non_modal_command == NON_MODAL_NO_ACTION)) { FAIL(STATUS_INVALID_JOG_COMMAND); }
+
+ // Initialize planner data to current spindle and coolant modal state.
+ pl_data->spindle_speed = gc_state.spindle_speed;
+ plan_data.condition = (gc_state.modal.spindle | gc_state.modal.coolant);
+
+ uint8_t status = jog_execute(&plan_data, &gc_block);
+ if (status == STATUS_OK) { memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_block.values.xyz)); }
+ return(status);
}
-
+
// If in laser mode, setup laser power based on current and past parser conditions.
- if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
- if ( !((gc_block.modal.motion == MOTION_MODE_LINEAR) || (gc_block.modal.motion == MOTION_MODE_CW_ARC)
- || (gc_block.modal.motion == MOTION_MODE_CCW_ARC)) ) {
- gc_parser_flags |= GC_PARSER_LASER_DISABLE;
- }
- // M3 constant power laser requires planner syncs to update the laser in certain conditions.
- // certain conditions.
- if (gc_state.modal.spindle == SPINDLE_ENABLE_CW) {
- if ((gc_state.modal.motion == MOTION_MODE_LINEAR) || (gc_state.modal.motion == MOTION_MODE_CW_ARC)
- || (gc_state.modal.motion == MOTION_MODE_CCW_ARC)) {
- if (gc_parser_flags & GC_PARSER_LASER_DISABLE) {
- gc_parser_flags |= GC_PARSER_LASER_FORCE_SYNC; // Change from G1/2/3 motion mode.
- } else {
- // Any non-motion block with M3 enabled and G1/2/3 modal state requires a sync when
- // the spindle speed changes. It is otherwise passed onto the planner.
- if (gc_state.spindle_speed != gc_block.values.s) {
- // NOTE: A G1/2/3 motion will always have axis words and be in AXIS_COMMAND_MOTION_MODE.
- // A non-motion G1 or any non-modal command using axis words will alter axis_command.
- if (!(axis_words) || (axis_command != AXIS_COMMAND_MOTION_MODE )) {
- gc_parser_flags |= GC_PARSER_LASER_FORCE_SYNC;
+ if (bit_istrue(settings.flags, BITFLAG_LASER_MODE)) {
+ if (!((gc_block.modal.motion == MOTION_MODE_LINEAR) || (gc_block.modal.motion == MOTION_MODE_CW_ARC)
+ || (gc_block.modal.motion == MOTION_MODE_CCW_ARC))) {
+ gc_parser_flags |= GC_PARSER_LASER_DISABLE;
+ }
+
+ // Any motion mode with axis words is allowed to be passed from a spindle speed update.
+ // NOTE: G1 and G0 without axis words sets axis_command to none. G28/30 are intentionally omitted.
+ // TODO: Check sync conditions for M3 enabled motions that don't enter the planner. (zero length).
+ if (axis_words && (axis_command == AXIS_COMMAND_MOTION_MODE)) {
+ gc_parser_flags |= GC_PARSER_LASER_ISMOTION;
+ }
+ else {
+ // M3 constant power laser requires planner syncs to update the laser when changing between
+ // a G1/2/3 motion mode state and vice versa when there is no motion in the line.
+ if (gc_state.modal.spindle == SPINDLE_ENABLE_CW) {
+ if ((gc_state.modal.motion == MOTION_MODE_LINEAR) || (gc_state.modal.motion == MOTION_MODE_CW_ARC)
+ || (gc_state.modal.motion == MOTION_MODE_CCW_ARC)) {
+ if (bit_istrue(gc_parser_flags, GC_PARSER_LASER_DISABLE)) {
+ gc_parser_flags |= GC_PARSER_LASER_FORCE_SYNC; // Change from G1/2/3 motion mode.
}
}
- }
- } else {
- // When changing to a G1 motion mode without axis words from a non-G1/2/3 motion mode.
- if (bit_isfalse(gc_parser_flags,GC_PARSER_LASER_DISABLE)) {
- if (!(axis_words) || (axis_command != AXIS_COMMAND_MOTION_MODE )) {
- gc_parser_flags |= GC_PARSER_LASER_FORCE_SYNC;
+ else {
+ // When changing to a G1 motion mode without axis words from a non-G1/2/3 motion mode.
+ if (bit_isfalse(gc_parser_flags, GC_PARSER_LASER_DISABLE)) {
+ gc_parser_flags |= GC_PARSER_LASER_FORCE_SYNC;
+ }
}
}
- }
- }
+ }
}
// [0. Non-specific/common error-checks and miscellaneous setup]:
@@ -906,23 +917,26 @@ uint8_t gc_execute_line(char *line)
pl_data->feed_rate = gc_state.feed_rate; // Record data for planner use.
// [4. Set spindle speed ]:
- if ((gc_state.spindle_speed != gc_block.values.s) || bit_istrue(gc_parser_flags,GC_PARSER_LASER_FORCE_SYNC)) {
- if (gc_state.modal.spindle != SPINDLE_DISABLE) {
- #ifdef VARIABLE_SPINDLE
- if (bit_istrue(gc_parser_flags,GC_PARSER_LASER_DISABLE)) {
- spindle_sync(gc_state.modal.spindle, 0.0);
- } else { spindle_sync(gc_state.modal.spindle, gc_block.values.s); }
- #else
- spindle_sync(gc_state.modal.spindle, 0.0);
- #endif
- }
- gc_state.spindle_speed = gc_block.values.s; // Update spindle speed state.
+ if ((gc_state.spindle_speed != gc_block.values.s) || bit_istrue(gc_parser_flags, GC_PARSER_LASER_FORCE_SYNC)) {
+ if (gc_state.modal.spindle != SPINDLE_DISABLE) {
+#ifdef VARIABLE_SPINDLE
+ if (bit_isfalse(gc_parser_flags, GC_PARSER_LASER_ISMOTION)) {
+ if (bit_istrue(gc_parser_flags, GC_PARSER_LASER_DISABLE)) {
+ spindle_sync(gc_state.modal.spindle, 0.0);
+ }
+ else { spindle_sync(gc_state.modal.spindle, gc_block.values.s); }
+ }
+#else
+ spindle_sync(gc_state.modal.spindle, 0.0);
+#endif
+ }
+ gc_state.spindle_speed = gc_block.values.s; // Update spindle speed state.
}
// NOTE: Pass zero spindle speed for all restricted laser motions.
- if (bit_isfalse(gc_parser_flags,GC_PARSER_LASER_DISABLE)) {
- pl_data->spindle_speed = gc_state.spindle_speed; // Record data for planner use.
+ if (bit_isfalse(gc_parser_flags, GC_PARSER_LASER_DISABLE)) {
+ pl_data->spindle_speed = gc_state.spindle_speed; // Record data for planner use.
} // else { pl_data->spindle_speed = 0.0; } // Initialized as zero already.
-
+
// [5. Select tool ]: NOT SUPPORTED. Only tracks tool value.
gc_state.tool = gc_block.values.t;
@@ -948,7 +962,13 @@ uint8_t gc_execute_line(char *line)
}
pl_data->condition |= gc_state.modal.coolant; // Set condition flag for planner use.
- // [9. Enable/disable feed rate or spindle overrides ]: NOT SUPPORTED. Always enabled.
+ // [9. Override control ]: NOT SUPPORTED. Always enabled. Except for a Grbl-only parking control.
+#ifdef ENABLE_PARKING_OVERRIDE_CONTROL
+ if (gc_state.modal.override != gc_block.modal.override) {
+ gc_state.modal.override = gc_block.modal.override;
+ mc_override_ctrl_update(gc_state.modal.override);
+ }
+#endif
// [10. Dwell ]:
if (gc_block.non_modal_command == NON_MODAL_DWELL) { mc_dwell(gc_block.values.p); }
@@ -969,7 +989,7 @@ uint8_t gc_execute_line(char *line)
if (axis_command == AXIS_COMMAND_TOOL_LENGTH_OFFSET ) { // Indicates a change.
gc_state.modal.tool_length = gc_block.modal.tool_length;
if (gc_state.modal.tool_length == TOOL_LENGTH_OFFSET_CANCEL) { // G49
- gc_block.values.xyz[TOOL_LENGTH_OFFSET_AXIS] = 0.0;
+ gc_block.values.xyz[TOOL_LENGTH_OFFSET_AXIS] = 0.0f;
} // else G43.1
if ( gc_state.tool_length_offset != gc_block.values.xyz[TOOL_LENGTH_OFFSET_AXIS] ) {
gc_state.tool_length_offset = gc_block.values.xyz[TOOL_LENGTH_OFFSET_AXIS];
@@ -1040,8 +1060,8 @@ uint8_t gc_execute_line(char *line)
pl_data->condition |= PL_COND_FLAG_RAPID_MOTION; // Set rapid motion condition flag.
mc_line(gc_block.values.xyz, pl_data);
} else if ((gc_state.modal.motion == MOTION_MODE_CW_ARC) || (gc_state.modal.motion == MOTION_MODE_CCW_ARC)) {
- mc_arc(gc_block.values.xyz, pl_data, gc_state.position, gc_block.values.ijk, gc_block.values.r,
- axis_0, axis_1, axis_linear, bit_istrue(gc_parser_flags,GC_PARSER_ARC_IS_CLOCKWISE));
+ mc_arc(gc_block.values.xyz, pl_data, gc_state.position, gc_block.values.ijk, gc_block.values.r,
+ axis_0, axis_1, axis_linear, bit_istrue(gc_parser_flags, GC_PARSER_ARC_IS_CLOCKWISE));
} else {
// NOTE: gc_block.values.xyz is returned from mc_probe_cycle with the updated position value. So
// upon a successful probing cycle, the machine position and the returned value should be the same.
@@ -1049,7 +1069,7 @@ uint8_t gc_execute_line(char *line)
pl_data->condition |= PL_COND_FLAG_NO_FEED_OVERRIDE;
#endif
gc_update_pos = mc_probe_cycle(gc_block.values.xyz, pl_data, gc_parser_flags);
- }
+ }
// As far as the parser is concerned, the position is now == target. In reality the
// motion control system might still be processing the action and the real tool position
@@ -1060,6 +1080,7 @@ uint8_t gc_execute_line(char *line)
gc_sync_position(); // gc_state.position[] = sys_position
} // == GC_UPDATE_POS_NONE
}
+
}
// [21. Program flow ]:
@@ -1086,7 +1107,13 @@ uint8_t gc_execute_line(char *line)
gc_state.modal.coord_select = 0; // G54
gc_state.modal.spindle = SPINDLE_DISABLE;
gc_state.modal.coolant = COOLANT_DISABLE;
- // gc_state.modal.override = OVERRIDE_DISABLE; // Not supported.
+ #ifdef ENABLE_PARKING_OVERRIDE_CONTROL
+ #ifdef DEACTIVATE_PARKING_UPON_INIT
+ gc_state.modal.override = OVERRIDE_DISABLED;
+ #else
+ gc_state.modal.override = OVERRIDE_PARKING_MOTION;
+ #endif
+ #endif
#ifdef RESTORE_OVERRIDES_AFTER_PROGRAM_END
sys.f_override = DEFAULT_FEED_OVERRIDE;
@@ -1098,7 +1125,7 @@ uint8_t gc_execute_line(char *line)
if (sys.state != STATE_CHECK_MODE) {
if (!(settings_read_coord_data(gc_state.modal.coord_select,gc_state.coord_system))) { FAIL(STATUS_SETTING_READ_FAIL); }
system_flag_wco_change(); // Set to refresh immediately just in case something altered.
- spindle_set_state(SPINDLE_DISABLE,0.0);
+ spindle_set_state(SPINDLE_DISABLE,0.0f);
coolant_set_state(COOLANT_DISABLE);
}
report_feedback_message(MESSAGE_PROGRAM_END);
@@ -1132,7 +1159,7 @@ uint8_t gc_execute_line(char *line)
group 7 = {G41, G42} cutter radius compensation (G40 is supported)
group 8 = {G43} tool length offset (G43.1/G49 are supported)
group 8 = {M7*} enable mist coolant (* Compile-option)
- group 9 = {M48, M49} enable/disable feed and speed override switches
- group 10 = {G98, G99} return mode canned cycles
+ group 9 = {M48, M49, M56*} enable/disable override switches (* Compile-option)
+ group 10 = {G98, G99} return mode canned cycles
group 13 = {G61.1, G64} path control mode (G61 is supported)
*/
diff --git a/grbl/gcode.h b/grbl/gcode.h
index f13f07e7..26a74b58 100644
--- a/grbl/gcode.h
+++ b/grbl/gcode.h
@@ -44,10 +44,7 @@
#define MODAL_GROUP_M4 11 // [M0,M1,M2,M30] Stopping
#define MODAL_GROUP_M7 12 // [M3,M4,M5] Spindle turning
#define MODAL_GROUP_M8 13 // [M7,M8,M9] Coolant control
-
-// #define OTHER_INPUT_F 14
-// #define OTHER_INPUT_S 15
-// #define OTHER_INPUT_T 16
+#define MODAL_GROUP_M9 14 // [M56] Override control
// Define command actions for within execution-type modal groups (motion, stopping, non-modal). Used
// internally by the parser to know which command to execute.
@@ -126,6 +123,15 @@
#define TOOL_LENGTH_OFFSET_CANCEL 0 // G49 (Default: Must be zero)
#define TOOL_LENGTH_OFFSET_ENABLE_DYNAMIC 1 // G43.1
+// Modal Group M9: Override control
+#ifdef DEACTIVATE_PARKING_UPON_INIT
+ #define OVERRIDE_DISABLED 0 // (Default: Must be zero)
+ #define OVERRIDE_PARKING_MOTION 1 // M56
+#else
+ #define OVERRIDE_PARKING_MOTION 0 // M56 (Default: Must be zero)
+ #define OVERRIDE_DISABLED 1 // Parking disabled.
+#endif
+
// Modal Group G12: Active work coordinate system
// N/A: Stores coordinate system value (54-59) to change to.
@@ -169,6 +175,7 @@
#define GC_PARSER_PROBE_IS_NO_ERROR bit(4)
#define GC_PARSER_LASER_FORCE_SYNC bit(5)
#define GC_PARSER_LASER_DISABLE bit(6)
+#define GC_PARSER_LASER_ISMOTION bit(7)
// NOTE: When this struct is zeroed, the above defines set the defaults for the system.
@@ -186,6 +193,7 @@ typedef struct {
uint8_t program_flow; // {M0,M1,M2,M30}
uint8_t coolant; // {M7,M8,M9}
uint8_t spindle; // {M3,M4,M5}
+ uint8_t override; // {M56}
} gc_modal_t;
typedef struct {
diff --git a/grbl/grbl.h b/grbl/grbl.h
index 9879a30b..a0b1f9b0 100644
--- a/grbl/grbl.h
+++ b/grbl/grbl.h
@@ -22,21 +22,68 @@
#define grbl_h
// Grbl versioning system
-#define GRBL_VERSION "1.1e"
-#define GRBL_VERSION_BUILD "20161203"
+#define GRBL_VERSION "1.1f"
+#define GRBL_VERSION_BUILD "20170801"
+
+#if !defined(STM32F103C8) && !defined(WIN32)
+#define AVRTARGET
+#endif
// Define standard libraries used by Grbl.
+#ifdef AVRTARGET
#include
#include
#include
#include
#include
-#include
#include
+#include
+#define PORTPINDEF uint8_t
+#endif
+#include
+#ifdef WIN32
+#include
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef signed long long int64_t;
+typedef unsigned long long uint64_t;
+typedef int bool;
+#define false 0
+#define true 1
+#define truncf(x) (int32_t)x
+#define PSTR(x) x
+#define pgm_read_byte_near(x) *(x)
+#define _delay_ms(x) Sleep(x)
+#define M_PI 3.1415926f
+#define LOG(x,y)
+#define PORTPINDEF uint8_t
+#define printPgmString printString
+//#define NOEEPROMSUPPORT
+#endif
+#ifdef STM32F103C8
+#include "stm32f10x.h"
+#include "stm32f10x_gpio.h"
+#include "stm32f10x_exti.h"
+#include "stm32f10x_tim.h"
+#include "misc.h"
+#define PSTR(x) x
+#define pgm_read_byte_near(x) *(x)
+void _delay_ms(uint32_t x);
+void _delay_us(uint32_t x);
+#define false 0
+#define true 1
+#define PORTPINDEF uint16_t
+typedef int bool;
+//#define NOEEPROMSUPPORT
+#define printPgmString printString
+#endif
#include
#include
#include
-#include
// Define the Grbl system include files. NOTE: Do not alter organization.
#include "config.h"
@@ -76,15 +123,25 @@
#error "USE_SPINDLE_DIR_AS_ENABLE_PIN may only be used with a 328p processor"
#endif
+#if !defined(USE_SPINDLE_DIR_AS_ENABLE_PIN) && defined(SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED)
+ #error "SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED may only be used with USE_SPINDLE_DIR_AS_ENABLE_PIN enabled"
+#endif
+
#if defined(PARKING_ENABLE)
#if defined(HOMING_FORCE_SET_ORIGIN)
#error "HOMING_FORCE_SET_ORIGIN is not supported with PARKING_ENABLE at this time."
#endif
#endif
-#if defined(SPINDLE_MINIMUM_PWM)
- #if !(SPINDLE_MINIMUM_PWM > 0)
- #error "SPINDLE_MINIMUM_PWM must be greater than zero."
+#if defined(ENABLE_PARKING_OVERRIDE_CONTROL)
+ #if !defined(PARKING_ENABLE)
+ #error "ENABLE_PARKING_OVERRIDE_CONTROL must be enabled with PARKING_ENABLE."
+ #endif
+#endif
+
+#if defined(SPINDLE_PWM_MIN_VALUE)
+ #if !(SPINDLE_PWM_MIN_VALUE > 0)
+ #error "SPINDLE_PWM_MIN_VALUE must be greater than zero."
#endif
#endif
diff --git a/grbl/jog.c b/grbl/jog.c
index e08119b1..bc61a204 100644
--- a/grbl/jog.c
+++ b/grbl/jog.c
@@ -1,21 +1,21 @@
/*
- jog.h - Jogging methods
- Part of Grbl
+jog.h - Jogging methods
+Part of Grbl
- Copyright (c) 2016 Sungeun K. Jeon for Gnea Research LLC
+Copyright (c) 2016 Sungeun K. Jeon for Gnea Research LLC
- Grbl is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
+Grbl is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
- Grbl is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+Grbl is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Grbl. If not, see .
+You should have received a copy of the GNU General Public License
+along with Grbl. If not, see .
*/
#include "grbl.h"
@@ -28,16 +28,16 @@ uint8_t jog_execute(plan_line_data_t *pl_data, parser_block_t *gc_block)
// NOTE: Spindle and coolant are allowed to fully function with overrides during a jog.
pl_data->feed_rate = gc_block->values.f;
pl_data->condition |= PL_COND_FLAG_NO_FEED_OVERRIDE;
- #ifdef USE_LINE_NUMBERS
- pl_data->line_number = gc_block.values.n;
- #endif
+#ifdef USE_LINE_NUMBERS
+ pl_data->line_number = gc_block->values.n;
+#endif
- if (bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE)) {
+ if (bit_istrue(settings.flags, BITFLAG_SOFT_LIMIT_ENABLE)) {
if (system_check_travel_limits(gc_block->values.xyz)) { return(STATUS_TRAVEL_EXCEEDED); }
}
// Valid jog command. Plan, set state, and execute.
- mc_line(gc_block->values.xyz,pl_data);
+ mc_line(gc_block->values.xyz, pl_data);
if (sys.state == STATE_IDLE) {
if (plan_get_current_block() != NULL) { // Check if there is a block to execute.
sys.state = STATE_JOG;
diff --git a/grbl/limits.c b/grbl/limits.c
index 7e642942..3bd1c44b 100644
--- a/grbl/limits.c
+++ b/grbl/limits.c
@@ -24,14 +24,15 @@
// Homing axis search distance multiplier. Computed by this value times the cycle travel.
#ifndef HOMING_AXIS_SEARCH_SCALAR
- #define HOMING_AXIS_SEARCH_SCALAR 1.5 // Must be > 1 to ensure limit switch will be engaged.
+ #define HOMING_AXIS_SEARCH_SCALAR 1.5f // Must be > 1 to ensure limit switch will be engaged.
#endif
#ifndef HOMING_AXIS_LOCATE_SCALAR
- #define HOMING_AXIS_LOCATE_SCALAR 5.0 // Must be > 1 to ensure limit switch is cleared.
+ #define HOMING_AXIS_LOCATE_SCALAR 5.0f // Must be > 1 to ensure limit switch is cleared.
#endif
void limits_init()
{
+#ifdef AVRTARGET
LIMIT_DDR &= ~(LIMIT_MASK); // Set as input pins
#ifdef DISABLE_LIMIT_PIN_PULL_UP
@@ -52,14 +53,53 @@ void limits_init()
WDTCSR |= (1<CR1 |= (USART_CR1_RE | USART_CR1_TE);
+ USART_Init(USART1, &USART_InitStructure);
+ // USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
+ USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
+ USART_Cmd(USART1, ENABLE);
+}
+#endif
+
+#endif
+#ifdef WIN32
+int main(int argc, char *argv[])
+#else
int main(void)
+#endif
{
+#if defined (STM32F103C8)
+ GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);
+#ifdef LEDBLINK
+ GPIO_InitTypeDef GPIO_InitStructure;
+
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
+ GPIO_Init(GPIOC, &GPIO_InitStructure);
+#endif
+ //Set_System();
+#ifndef USEUSB
+ USART1_Configuration(115200);
+#else
+ Set_USBClock();
+ USB_Interrupts_Config();
+ USB_Init();
+#endif
+
+#ifndef NOEEPROMSUPPORT
+ FLASH_Unlock();
+ eeprom_init();
+#endif
+ SysTick->CTRL &= 0xfffffffb;
+#endif
// Initialize system upon power-up.
serial_init(); // Setup serial baud rate and interrupts
+#ifdef WIN32
+ winserial_init(argv[1]);
+ eeprom_init();
+#endif
settings_init(); // Load Grbl settings from EEPROM
stepper_init(); // Configure stepper pins and interrupt timers
system_init(); // Configure pinout pins and pin-change interrupt
memset(sys_position,0,sizeof(sys_position)); // Clear machine position.
+#ifdef AVRTARGET
sei(); // Enable interrupts
-
+#endif
// Initialize system state.
#ifdef FORCE_INITIALIZATION_ALARM
// Force Grbl into an ALARM state upon a power-cycle or hard reset.
@@ -97,3 +189,24 @@ int main(void)
}
return 0; /* Never reached */
}
+#if defined (STM32F103C8)
+void _delay_ms(uint32_t x)
+{
+ u32 temp;
+ SysTick->LOAD = (u32)72000000 / 8000; // Loading time
+ SysTick->VAL = 0x00; // Empty the counter
+ SysTick->CTRL = 0x01; // Start from bottom
+ do
+ {
+ temp = SysTick->CTRL;
+ } while (temp & 0x01 && !(temp&(1 << 16))); // Wait time arrive
+ SysTick->CTRL = 0x00; // Close the counter
+ SysTick->VAL = 0X00; // Empty the counter
+}
+void LedBlink(void)
+{
+ static BitAction nOnFlag = Bit_SET;
+ GPIO_WriteBit(GPIOC, GPIO_Pin_13, nOnFlag);
+ nOnFlag = (nOnFlag == Bit_SET) ? Bit_RESET : Bit_SET;
+}
+#endif
diff --git a/grbl/motion_control.c b/grbl/motion_control.c
index 4e226e41..0ebe8eb2 100644
--- a/grbl/motion_control.c
+++ b/grbl/motion_control.c
@@ -65,8 +65,15 @@ void mc_line(float *target, plan_line_data_t *pl_data)
} while (1);
// Plan and queue motion into planner buffer
- // uint8_t plan_status; // Not used in normal operation.
- plan_buffer_line(target, pl_data);
+ if (plan_buffer_line(target, pl_data) == PLAN_EMPTY_BLOCK) {
+ if (bit_istrue(settings.flags, BITFLAG_LASER_MODE)) {
+ // Correctly set spindle state, if there is a coincident position passed. Forces a buffer
+ // sync while in M3 laser mode only.
+ if (pl_data->condition & PL_COND_FLAG_SPINDLE_CW) {
+ spindle_sync(PL_COND_FLAG_SPINDLE_CW, pl_data->spindle_speed);
+ }
+ }
+ }
}
@@ -88,7 +95,7 @@ void mc_arc(float *target, plan_line_data_t *pl_data, float *position, float *of
float rt_axis1 = target[axis_1] - center_axis1;
// CCW angle between position and target from circle center. Only one atan2() trig computation required.
- float angular_travel = atan2(r_axis0*rt_axis1-r_axis1*rt_axis0, r_axis0*rt_axis0+r_axis1*rt_axis1);
+ float angular_travel = atan2f(r_axis0*rt_axis1-r_axis1*rt_axis0, r_axis0*rt_axis0+r_axis1*rt_axis1);
if (is_clockwise_arc) { // Correct atan2 output per direction
if (angular_travel >= -ARC_ANGULAR_TRAVEL_EPSILON) { angular_travel -= 2*M_PI; }
} else {
@@ -99,8 +106,8 @@ void mc_arc(float *target, plan_line_data_t *pl_data, float *position, float *of
// (2x) settings.arc_tolerance. For 99% of users, this is just fine. If a different arc segment fit
// is desired, i.e. least-squares, midpoint on arc, just change the mm_per_arc_segment calculation.
// For the intended uses of Grbl, this value shouldn't exceed 2000 for the strictest of cases.
- uint16_t segments = floor(fabs(0.5*angular_travel*radius)/
- sqrt(settings.arc_tolerance*(2*radius - settings.arc_tolerance)) );
+ uint16_t segments = (uint16_t)floorf(fabsf(0.5f*angular_travel*radius) /
+ sqrtf(settings.arc_tolerance*(2*radius - settings.arc_tolerance)) );
if (segments) {
// Multiply inverse feed_rate to compensate for the fact that this movement is approximated
@@ -140,8 +147,8 @@ void mc_arc(float *target, plan_line_data_t *pl_data, float *position, float *of
This is important when there are successive arc motions.
*/
// Computes: cos_T = 1 - theta_per_segment^2/2, sin_T = theta_per_segment - theta_per_segment^3/6) in ~52usec
- float cos_T = 2.0 - theta_per_segment*theta_per_segment;
- float sin_T = theta_per_segment*0.16666667*(cos_T + 4.0);
+ float cos_T = 2.0f - theta_per_segment*theta_per_segment;
+ float sin_T = theta_per_segment*0.16666667f*(cos_T + 4.0f);
cos_T *= 0.5;
float sin_Ti;
@@ -161,8 +168,8 @@ void mc_arc(float *target, plan_line_data_t *pl_data, float *position, float *of
} else {
// Arc correction to radius vector. Computed only every N_ARC_CORRECTION increments. ~375 usec
// Compute exact location by applying transformation matrix from initial radius vector(=-offset).
- cos_Ti = cos(i*theta_per_segment);
- sin_Ti = sin(i*theta_per_segment);
+ cos_Ti = cosf(i*theta_per_segment);
+ sin_Ti = sinf(i*theta_per_segment);
r_axis0 = -offset[axis_0]*cos_Ti + offset[axis_1]*sin_Ti;
r_axis1 = -offset[axis_0]*sin_Ti - offset[axis_1]*cos_Ti;
count = 0;
@@ -240,7 +247,13 @@ void mc_homing_cycle(uint8_t cycle_mask)
plan_sync_position();
// If hard limits feature enabled, re-enable hard limits pin change register after homing cycle.
- limits_init();
+#ifdef STM32F103C8
+ EXTI_ClearITPendingBit((1 << X_LIMIT_BIT) | (1 << Y_LIMIT_BIT) | (1 << Z_LIMIT_BIT));
+ NVIC_ClearPendingIRQ(EXTI15_10_IRQn);
+ NVIC_EnableIRQ(EXTI15_10_IRQn);
+#else
+ limits_init();
+#endif
}
@@ -256,8 +269,8 @@ uint8_t mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t parser_
if (sys.abort) { return(GC_PROBE_ABORT); } // Return if system reset has been issued.
// Initialize probing control variables
- uint8_t is_probe_away = bit_istrue(parser_flags,GC_PARSER_PROBE_IS_AWAY);
- uint8_t is_no_error = bit_istrue(parser_flags,GC_PARSER_PROBE_IS_NO_ERROR);
+ uint8_t is_probe_away = bit_istrue(parser_flags, GC_PARSER_PROBE_IS_AWAY);
+ uint8_t is_no_error = bit_istrue(parser_flags, GC_PARSER_PROBE_IS_NO_ERROR);
sys.probe_succeeded = false; // Re-initialize probe history before beginning cycle.
probe_configure_invert_mask(is_probe_away);
@@ -310,34 +323,43 @@ uint8_t mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t parser_
else { return(GC_PROBE_FAIL_END); } // Failed to trigger probe within travel. With or without error.
}
-
-// Plans and executes the single special motion case for parking. Independent of main planner buffer.
-// NOTE: Uses the always free planner ring buffer head to store motion parameters for execution.
-void mc_parking_motion(float *parking_target, plan_line_data_t *pl_data)
-{
- if (sys.abort) { return; } // Block during abort.
-
- uint8_t plan_status = plan_buffer_line(parking_target, pl_data);
-
- if (plan_status) {
- bit_true(sys.step_control, STEP_CONTROL_EXECUTE_SYS_MOTION);
- bit_false(sys.step_control, STEP_CONTROL_END_MOTION); // Allow parking motion to execute, if feed hold is active.
- st_parking_setup_buffer(); // Setup step segment buffer for special parking motion case
- st_prep_buffer();
- st_wake_up();
- do {
+#ifdef PARKING_ENABLE
+ void mc_parking_motion(float *parking_target, plan_line_data_t *pl_data)
+ {
+ if (sys.abort) { return; } // Block during abort.
+
+ uint8_t plan_status = plan_buffer_line(parking_target, pl_data);
+
+ if (plan_status) {
+ bit_true(sys.step_control, STEP_CONTROL_EXECUTE_SYS_MOTION);
+ bit_false(sys.step_control, STEP_CONTROL_END_MOTION); // Allow parking motion to execute, if feed hold is active.
+ st_parking_setup_buffer(); // Setup step segment buffer for special parking motion case
+ st_prep_buffer();
+ st_wake_up();
+ do {
+ protocol_exec_rt_system();
+ if (sys.abort) { return; }
+ } while (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION);
+ st_parking_restore_buffer(); // Restore step segment buffer to normal run state.
+ }
+ else {
+ bit_false(sys.step_control, STEP_CONTROL_EXECUTE_SYS_MOTION);
protocol_exec_rt_system();
- if (sys.abort) { return; }
- } while (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION);
- st_parking_restore_buffer(); // Restore step segment buffer to normal run state.
- } else {
- bit_false(sys.step_control, STEP_CONTROL_EXECUTE_SYS_MOTION);
- protocol_exec_rt_system();
- }
+ }
-}
+ }
+#endif
+#ifdef ENABLE_PARKING_OVERRIDE_CONTROL
+void mc_override_ctrl_update(uint8_t override_state)
+{
+ // Finish all queued commands before altering override control state
+ protocol_buffer_synchronize();
+ if (sys.abort) { return; }
+ sys.override_ctrl = override_state;
+}
+#endif
// Method to ready the system to reset by setting the realtime reset command and killing any
// active processes in the system. This also checks if a system reset is issued while Grbl
// is in a motion state. If so, kills the steppers and sets the system alarm to flag position
@@ -359,7 +381,9 @@ void mc_reset()
// violated, by which, all bets are off.
if ((sys.state & (STATE_CYCLE | STATE_HOMING | STATE_JOG)) ||
(sys.step_control & (STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_SYS_MOTION))) {
- if (sys.state == STATE_HOMING) { system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_RESET); }
+ if (sys.state == STATE_HOMING) {
+ if (!sys_rt_exec_alarm) { system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_RESET); }
+ }
else { system_set_exec_alarm(EXEC_ALARM_ABORT_CYCLE); }
st_go_idle(); // Force kill steppers. Position has likely been lost.
}
diff --git a/grbl/motion_control.h b/grbl/motion_control.h
index 307afeb7..0f7531e3 100644
--- a/grbl/motion_control.h
+++ b/grbl/motion_control.h
@@ -54,6 +54,9 @@ void mc_homing_cycle(uint8_t cycle_mask);
// Perform tool length probe cycle. Requires probe switch.
uint8_t mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t parser_flags);
+// Handles updating the override control state.
+void mc_override_ctrl_update(uint8_t override_state);
+
// Plans and executes the single special motion case for parking. Independent of main planner buffer.
void mc_parking_motion(float *parking_target, plan_line_data_t *pl_data);
diff --git a/grbl/nuts_bolts.c b/grbl/nuts_bolts.c
index 9d89a8d0..ce3d51f9 100644
--- a/grbl/nuts_bolts.c
+++ b/grbl/nuts_bolts.c
@@ -83,14 +83,14 @@ uint8_t read_float(char *line, uint8_t *char_counter, float *float_ptr)
// expected range of E0 to E-4.
if (fval != 0) {
while (exp <= -2) {
- fval *= 0.01;
+ fval *= 0.01f;
exp += 2;
}
if (exp < 0) {
- fval *= 0.1;
+ fval *= 0.1f;
} else if (exp > 0) {
do {
- fval *= 10.0;
+ fval *= 10.0f;
} while (--exp > 0);
}
}
@@ -111,7 +111,7 @@ uint8_t read_float(char *line, uint8_t *char_counter, float *float_ptr)
// Non-blocking delay function used for general operation and suspend features.
void delay_sec(float seconds, uint8_t mode)
{
- uint16_t i = ceil(1000/DWELL_TIME_STEP*seconds);
+ uint16_t i = (uint16_t)ceilf(1000 / DWELL_TIME_STEP*seconds);
while (i-- > 0) {
if (sys.abort) { return; }
if (mode == DELAY_MODE_DWELL) {
@@ -134,44 +134,21 @@ void delay_ms(uint16_t ms)
}
-// Delays variable defined microseconds. Compiler compatibility fix for _delay_us(),
-// which only accepts constants in future compiler releases. Written to perform more
-// efficiently with larger delays, as the counter adds parasitic time in each iteration.
-void delay_us(uint32_t us)
-{
- while (us) {
- if (us < 10) {
- _delay_us(1);
- us--;
- } else if (us < 100) {
- _delay_us(10);
- us -= 10;
- } else if (us < 1000) {
- _delay_us(100);
- us -= 100;
- } else {
- _delay_ms(1);
- us -= 1000;
- }
- }
-}
-
-
// Simple hypotenuse computation function.
-float hypot_f(float x, float y) { return(sqrt(x*x + y*y)); }
+float hypot_f(float x, float y) { return(sqrtf(x*x + y*y)); }
float convert_delta_vector_to_unit_vector(float *vector)
{
uint8_t idx;
- float magnitude = 0.0;
+ float magnitude = 0.0f;
for (idx=0; idxprogrammed_rate;
- if (block->condition & PL_COND_FLAG_RAPID_MOTION) { nominal_speed *= (0.01*sys.r_override); }
+ if (block->condition & PL_COND_FLAG_RAPID_MOTION) { nominal_speed *= (0.01f*sys.r_override); }
else {
- if (!(block->condition & PL_COND_FLAG_NO_FEED_OVERRIDE)) { nominal_speed *= (0.01*sys.f_override); }
+ if (!(block->condition & PL_COND_FLAG_NO_FEED_OVERRIDE)) { nominal_speed *= (0.01f*sys.f_override); }
if (nominal_speed > block->rapid_rate) { nominal_speed = block->rapid_rate; }
}
if (nominal_speed > MINIMUM_FEED_RATE) { return(nominal_speed); }
@@ -331,15 +331,16 @@ uint8_t plan_buffer_line(float *target, plan_line_data_t *pl_data)
uint8_t idx;
// Copy position data based on type of motion being planned.
- if (block->condition & PL_COND_FLAG_SYSTEM_MOTION) {
- #ifdef COREXY
- position_steps[X_AXIS] = system_convert_corexy_to_x_axis_steps(sys_position);
- position_steps[Y_AXIS] = system_convert_corexy_to_y_axis_steps(sys_position);
- position_steps[Z_AXIS] = sys_position[Z_AXIS];
- #else
- memcpy(position_steps, sys_position, sizeof(sys_position));
- #endif
- } else { memcpy(position_steps, pl.position, sizeof(pl.position)); }
+ if (block->condition & PL_COND_FLAG_SYSTEM_MOTION) {
+#ifdef COREXY
+ position_steps[X_AXIS] = system_convert_corexy_to_x_axis_steps(sys_position);
+ position_steps[Y_AXIS] = system_convert_corexy_to_y_axis_steps(sys_position);
+ position_steps[Z_AXIS] = sys_position[Z_AXIS];
+#else
+ memcpy(position_steps, sys_position, sizeof(sys_position));
+#endif
+ }
+ else { memcpy(position_steps, pl.position, sizeof(pl.position)); }
#ifdef COREXY
target_steps[A_MOTOR] = lround(target[A_MOTOR]*settings.steps_per_mm[A_MOTOR]);
@@ -354,8 +355,8 @@ uint8_t plan_buffer_line(float *target, plan_line_data_t *pl_data)
// NOTE: Computes true distance from converted step values.
#ifdef COREXY
if ( !(idx == A_MOTOR) && !(idx == B_MOTOR) ) {
- target_steps[idx] = lround(target[idx]*settings.steps_per_mm[idx]);
- block->steps[idx] = labs(target_steps[idx]-position_steps[idx]);
+ target_steps[idx] = lroundf(target[idx]*settings.steps_per_mm[idx]);
+ block->steps[idx] = fabsf(target_steps[idx]-position_steps[idx]);
}
block->step_event_count = max(block->step_event_count, block->steps[idx]);
if (idx == A_MOTOR) {
@@ -366,15 +367,15 @@ uint8_t plan_buffer_line(float *target, plan_line_data_t *pl_data)
delta_mm = (target_steps[idx] - position_steps[idx])/settings.steps_per_mm[idx];
}
#else
- target_steps[idx] = lround(target[idx]*settings.steps_per_mm[idx]);
- block->steps[idx] = labs(target_steps[idx]-position_steps[idx]);
+ target_steps[idx] = lroundf(target[idx]*settings.steps_per_mm[idx]);
+ block->steps[idx] = abs(target_steps[idx]-position_steps[idx]);
block->step_event_count = max(block->step_event_count, block->steps[idx]);
delta_mm = (target_steps[idx] - position_steps[idx])/settings.steps_per_mm[idx];
#endif
unit_vec[idx] = delta_mm; // Store unit vector numerator
// Set direction bits. Bit enabled always means direction is negative.
- if (delta_mm < 0.0 ) { block->direction_bits |= get_direction_pin_mask(idx); }
+ if (delta_mm < 0.0f ) { block->direction_bits |= direction_pin_mask[idx]; }
}
// Bail if this is a zero-length block. Highly unlikely to occur.
@@ -400,8 +401,8 @@ uint8_t plan_buffer_line(float *target, plan_line_data_t *pl_data)
// Initialize block entry speed as zero. Assume it will be starting from rest. Planner will correct this later.
// If system motion, the system motion block always is assumed to start from rest and end at a complete stop.
- block->entry_speed_sqr = 0.0;
- block->max_junction_speed_sqr = 0.0; // Starting from rest. Enforce start from zero velocity.
+ block->entry_speed_sqr = 0.0f;
+ block->max_junction_speed_sqr = 0.0f; // Starting from rest. Enforce start from zero velocity.
} else {
// Compute maximum allowable entry speed at junction by centripetal acceleration approximation.
@@ -427,26 +428,26 @@ uint8_t plan_buffer_line(float *target, plan_line_data_t *pl_data)
// change the overall maximum entry speed conditions of all blocks.
float junction_unit_vec[N_AXIS];
- float junction_cos_theta = 0.0;
+ float junction_cos_theta = 0.0f;
for (idx=0; idx 0.999999) {
+ if (junction_cos_theta > 0.999999f) {
// For a 0 degree acute junction, just set minimum junction speed.
block->max_junction_speed_sqr = MINIMUM_JUNCTION_SPEED*MINIMUM_JUNCTION_SPEED;
} else {
- if (junction_cos_theta < -0.999999) {
+ if (junction_cos_theta < -0.999999f) {
// Junction is a straight line or 180 degrees. Junction speed is infinite.
block->max_junction_speed_sqr = SOME_LARGE_VALUE;
} else {
convert_delta_vector_to_unit_vector(junction_unit_vec);
float junction_acceleration = limit_value_by_axis_maximum(settings.acceleration, junction_unit_vec);
- float sin_theta_d2 = sqrt(0.5*(1.0-junction_cos_theta)); // Trig half angle identity. Always positive.
+ float sin_theta_d2 = sqrtf(0.5f*(1.0f-junction_cos_theta)); // Trig half angle identity. Always positive.
block->max_junction_speed_sqr = max( MINIMUM_JUNCTION_SPEED*MINIMUM_JUNCTION_SPEED,
- (junction_acceleration * settings.junction_deviation * sin_theta_d2)/(1.0-sin_theta_d2) );
+ (junction_acceleration * settings.junction_deviation * sin_theta_d2)/(1.0f-sin_theta_d2) );
}
}
}
diff --git a/grbl/planner.h b/grbl/planner.h
index 9379dc3c..81ef4472 100644
--- a/grbl/planner.h
+++ b/grbl/planner.h
@@ -25,11 +25,15 @@
// The number of linear motions that can be in the plan at any give time
#ifndef BLOCK_BUFFER_SIZE
+#ifdef AVRTARGET
#ifdef USE_LINE_NUMBERS
#define BLOCK_BUFFER_SIZE 15
#else
#define BLOCK_BUFFER_SIZE 16
#endif
+#else
+#define BLOCK_BUFFER_SIZE 36
+#endif
#endif
// Returned status message from planner.
diff --git a/grbl/print.c b/grbl/print.c
index 771e3996..d4ba6986 100644
--- a/grbl/print.c
+++ b/grbl/print.c
@@ -28,7 +28,7 @@ void printString(const char *s)
serial_write(*s++);
}
-
+#ifdef AVRTARGET
// Print a string stored in PGM-memory
void printPgmString(const char *s)
{
@@ -36,7 +36,7 @@ void printPgmString(const char *s)
while ((c = pgm_read_byte_near(s++)))
serial_write(c);
}
-
+#endif
// void printIntegerInBase(unsigned long n, unsigned long base)
// {
@@ -81,7 +81,12 @@ void print_uint8_base10(uint8_t n)
// Prints an uint8 variable in base 2 with desired number of desired digits.
void print_uint8_base2_ndigit(uint8_t n, uint8_t digits) {
- unsigned char buf[digits];
+#if defined(AVRTARGET) || defined(STM32F103C8)
+ unsigned char buf[digits];
+#endif
+#ifdef WIN32
+ unsigned char buf[20];
+#endif
uint8_t i = 0;
for (; i < digits; i++) {
diff --git a/grbl/probe.c b/grbl/probe.c
index 60c9073a..985d5872 100644
--- a/grbl/probe.c
+++ b/grbl/probe.c
@@ -28,12 +28,26 @@ uint8_t probe_invert_mask;
// Probe pin initialization routine.
void probe_init()
{
+#ifdef AVRTARGET
PROBE_DDR &= ~(PROBE_MASK); // Configure as input pins
#ifdef DISABLE_PROBE_PIN_PULL_UP
PROBE_PORT &= ~(PROBE_MASK); // Normal low operation. Requires external pull-down.
#else
PROBE_PORT |= PROBE_MASK; // Enable internal pull-up resistors. Normal high operation.
#endif
+#endif
+#ifdef STM32F103C8
+ GPIO_InitTypeDef GPIO_InitStructure;
+ RCC_APB2PeriphClockCmd(RCC_PROBE_PORT, ENABLE);
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+#ifdef DISABLE_PROBE_PIN_PULL_UP
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
+#else
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
+#endif
+ GPIO_InitStructure.GPIO_Pin = PROBE_MASK;
+ GPIO_Init(PROBE_PORT, &GPIO_InitStructure);
+#endif
probe_configure_invert_mask(false); // Initialize invert mask.
}
@@ -50,7 +64,18 @@ void probe_configure_invert_mask(uint8_t is_probe_away)
// Returns the probe pin state. Triggered = true. Called by gcode parser and probe state monitor.
-uint8_t probe_get_state() { return((PROBE_PIN & PROBE_MASK) ^ probe_invert_mask); }
+uint8_t probe_get_state()
+{
+#ifdef AVRTARGET
+ return((PROBE_PIN & PROBE_MASK) ^ probe_invert_mask);
+#endif
+#ifdef WIN32
+ return 0;
+#endif
+#ifdef STM32F103C8
+ return ((GPIO_ReadInputData(PROBE_PORT) & PROBE_MASK) ^ probe_invert_mask) != 0;
+#endif
+}
// Monitors probe pin state and records the system position when detected. Called by the
diff --git a/grbl/protocol.c b/grbl/protocol.c
index dda09a87..070952a5 100644
--- a/grbl/protocol.c
+++ b/grbl/protocol.c
@@ -28,6 +28,9 @@
static char line[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated.
+#ifdef LEDBLINK
+void LedBlink(void);
+#endif
static void protocol_exec_rt_suspend();
@@ -82,7 +85,10 @@ void protocol_main_loop()
if (sys.abort) { return; } // Bail to calling function upon system abort
line[char_counter] = 0; // Set string termination character.
- #ifdef REPORT_ECHO_LINE_RECEIVED
+#ifdef LEDBLINK
+ LedBlink();
+#endif
+ #ifdef REPORT_ECHO_LINE_RECEIVED
report_echo_line_received(line);
#endif
@@ -234,7 +240,7 @@ void protocol_exec_rt_system()
// lost, continued streaming could cause a serious crash if by chance it gets executed.
} while (bit_isfalse(sys_rt_exec_state,EXEC_RESET));
}
- system_clear_exec_alarm_flag(0xFF); // Clear all alarm flags
+ system_clear_exec_alarm(); // Clear alarm
}
rt_exec = sys_rt_exec_state; // Copy volatile sys_rt_exec_state.
@@ -531,7 +537,7 @@ static void protocol_exec_rt_suspend()
restore_spindle_speed = block->spindle_speed;
}
#ifdef DISABLE_LASER_DURING_HOLD
- if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
+ if (bit_istrue(settings.flags, BITFLAG_LASER_MODE)) {
system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_STOP);
}
#endif
@@ -559,7 +565,7 @@ static void protocol_exec_rt_suspend()
#ifndef PARKING_ENABLE
- spindle_set_state(SPINDLE_DISABLE,0.0); // De-energize
+ spindle_set_state(SPINDLE_DISABLE,0.0f); // De-energize
coolant_set_state(COOLANT_DISABLE); // De-energize
#else
@@ -575,11 +581,17 @@ static void protocol_exec_rt_suspend()
// Execute slow pull-out parking retract motion. Parking requires homing enabled, the
// current location not exceeding the parking target location, and laser mode disabled.
// NOTE: State is will remain DOOR, until the de-energizing and retract is complete.
- if ((bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) &&
- (parking_target[PARKING_AXIS] < PARKING_TARGET) &&
- bit_isfalse(settings.flags,BITFLAG_LASER_MODE)) {
-
- // Retract spindle by pullout distance. Ensure retraction motion moves away from
+ #ifdef ENABLE_PARKING_OVERRIDE_CONTROL
+ if ((bit_istrue(settings.flags, BITFLAG_HOMING_ENABLE)) &&
+ (parking_target[PARKING_AXIS] < PARKING_TARGET) &&
+ bit_isfalse(settings.flags, BITFLAG_LASER_MODE) &&
+ (sys.override_ctrl == OVERRIDE_PARKING_MOTION)) {
+ #else
+ if ((bit_istrue(settings.flags, BITFLAG_HOMING_ENABLE)) &&
+ (parking_target[PARKING_AXIS] < PARKING_TARGET) &&
+ bit_isfalse(settings.flags, BITFLAG_LASER_MODE)) {
+ #endif
+ // Retract spindle by pullout distance. Ensure retraction motion moves away from
// the workpiece and waypoint motion doesn't exceed the parking target location.
if (parking_target[PARKING_AXIS] < retract_waypoint) {
parking_target[PARKING_AXIS] = retract_waypoint;
@@ -591,8 +603,8 @@ static void protocol_exec_rt_suspend()
// NOTE: Clear accessory state after retract and after an aborted restore motion.
pl_data->condition = (PL_COND_FLAG_SYSTEM_MOTION|PL_COND_FLAG_NO_FEED_OVERRIDE);
- pl_data->spindle_speed = 0.0;
- spindle_set_state(SPINDLE_DISABLE,0.0); // De-energize
+ pl_data->spindle_speed = 0.0f;
+ spindle_set_state(SPINDLE_DISABLE,0.0f); // De-energize
coolant_set_state(COOLANT_DISABLE); // De-energize
// Execute fast parking retract motion to parking target location.
@@ -606,7 +618,7 @@ static void protocol_exec_rt_suspend()
// Parking motion not possible. Just disable the spindle and coolant.
// NOTE: Laser mode does not start a parking motion to ensure the laser stops immediately.
- spindle_set_state(SPINDLE_DISABLE,0.0); // De-energize
+ spindle_set_state(SPINDLE_DISABLE,0.0f); // De-energize
coolant_set_state(COOLANT_DISABLE); // De-energize
}
@@ -622,7 +634,7 @@ static void protocol_exec_rt_suspend()
if (sys.state == STATE_SLEEP) {
report_feedback_message(MESSAGE_SLEEP_MODE);
// Spindle and coolant should already be stopped, but do it again just to be sure.
- spindle_set_state(SPINDLE_DISABLE,0.0); // De-energize
+ spindle_set_state(SPINDLE_DISABLE,0.0f); // De-energize
coolant_set_state(COOLANT_DISABLE); // De-energize
st_go_idle(); // Disable steppers
while (!(sys.abort)) { protocol_exec_rt_system(); } // Do nothing until reset.
@@ -642,7 +654,12 @@ static void protocol_exec_rt_suspend()
#ifdef PARKING_ENABLE
// Execute fast restore motion to the pull-out position. Parking requires homing enabled.
// NOTE: State is will remain DOOR, until the de-energizing and retract is complete.
- if ((settings.flags & (BITFLAG_HOMING_ENABLE|BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) {
+ #ifdef ENABLE_PARKING_OVERRIDE_CONTROL
+ if (((settings.flags & (BITFLAG_HOMING_ENABLE | BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) &&
+ (sys.override_ctrl == OVERRIDE_PARKING_MOTION)) {
+ #else
+ if ((settings.flags & (BITFLAG_HOMING_ENABLE | BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) {
+ #endif
// Check to ensure the motion doesn't move below pull-out position.
if (parking_target[PARKING_AXIS] <= PARKING_TARGET) {
parking_target[PARKING_AXIS] = retract_waypoint;
@@ -676,7 +693,12 @@ static void protocol_exec_rt_suspend()
#ifdef PARKING_ENABLE
// Execute slow plunge motion from pull-out position to resume position.
- if ((settings.flags & (BITFLAG_HOMING_ENABLE|BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) {
+ #ifdef ENABLE_PARKING_OVERRIDE_CONTROL
+ if (((settings.flags & (BITFLAG_HOMING_ENABLE | BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) &&
+ (sys.override_ctrl == OVERRIDE_PARKING_MOTION)) {
+ #else
+ if ((settings.flags & (BITFLAG_HOMING_ENABLE | BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) {
+ #endif
// Block if safety door re-opened during prior restore actions.
if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
// Regardless if the retract parking motion was a valid/safe motion or not, the
@@ -707,7 +729,7 @@ static void protocol_exec_rt_suspend()
// Handles beginning of spindle stop
if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_INITIATE) {
if (gc_state.modal.spindle != SPINDLE_DISABLE) {
- spindle_set_state(SPINDLE_DISABLE,0.0); // De-energize
+ spindle_set_state(SPINDLE_DISABLE,0.0f); // De-energize
sys.spindle_stop_ovr = SPINDLE_STOP_OVR_ENABLED; // Set stop override state to enabled, if de-energized.
} else {
sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED; // Clear stop override state
diff --git a/grbl/report.c b/grbl/report.c
index 62a4607d..a95b2534 100644
--- a/grbl/report.c
+++ b/grbl/report.c
@@ -91,19 +91,16 @@ static void report_util_setting_string(uint8_t n) {
}
*/
-#ifndef USE_CLASSIC_GRBL_INTERFACE
- static void report_util_uint8_setting(uint8_t n, int val) {
- report_util_setting_prefix(n);
- print_uint8_base10(val);
- report_util_line_feed(); // report_util_setting_string(n);
- }
- static void report_util_float_setting(uint8_t n, float val, uint8_t n_decimal) {
- report_util_setting_prefix(n);
- printFloat(val,n_decimal);
- report_util_line_feed(); // report_util_setting_string(n);
- }
-#endif
-
+static void report_util_uint8_setting(uint8_t n, int val) {
+ report_util_setting_prefix(n);
+ print_uint8_base10(val);
+ report_util_line_feed(); // report_util_setting_string(n);
+}
+static void report_util_float_setting(uint8_t n, float val, uint8_t n_decimal) {
+ report_util_setting_prefix(n);
+ printFloat(val, n_decimal);
+ report_util_line_feed(); // report_util_setting_string(n);
+}
// Handles the primary confirmation protocol response for streaming interfaces and human-feedback.
// For every incoming line, this method responds with an 'ok' for a successful command or an
@@ -111,95 +108,23 @@ static void report_util_setting_string(uint8_t n) {
// operation. Errors events can originate from the g-code parser, settings module, or asynchronously
// from a critical error, such as a triggered hard limit. Interface should always monitor for these
// responses.
-// NOTE: In REPORT_GUI_MODE, all error codes are greater than zero.
void report_status_message(uint8_t status_code)
{
switch(status_code) {
case STATUS_OK: // STATUS_OK
printPgmString(PSTR("ok\r\n")); break;
default:
- #ifdef USE_CLASSIC_GRBL_INTERFACE
- printPgmString(PSTR("error: "));
- switch(status_code) {
- case STATUS_EXPECTED_COMMAND_LETTER:
- printPgmString(PSTR("Expected command letter")); break;
- case STATUS_BAD_NUMBER_FORMAT:
- printPgmString(PSTR("Bad number format")); break;
- case STATUS_INVALID_STATEMENT:
- printPgmString(PSTR("Invalid statement")); break;
- case STATUS_NEGATIVE_VALUE:
- printPgmString(PSTR("Value < 0")); break;
- case STATUS_SETTING_DISABLED:
- printPgmString(PSTR("Setting disabled")); break;
- case STATUS_SETTING_STEP_PULSE_MIN:
- printPgmString(PSTR("Value < 3 usec")); break;
- case STATUS_SETTING_READ_FAIL:
- printPgmString(PSTR("EEPROM read fail. Using defaults")); break;
- case STATUS_IDLE_ERROR:
- printPgmString(PSTR("Not idle")); break;
- case STATUS_SYSTEM_GC_LOCK:
- printPgmString(PSTR("G-code lock")); break;
- case STATUS_SOFT_LIMIT_ERROR:
- printPgmString(PSTR("Homing not enabled")); break;
- case STATUS_OVERFLOW:
- printPgmString(PSTR("Line overflow")); break;
- #ifdef MAX_STEP_RATE_HZ
- case STATUS_MAX_STEP_RATE_EXCEEDED:
- printPgmString(PSTR("Step rate > 30kHz")); break;
- #endif
- case STATUS_CHECK_DOOR:
- printPgmString(PSTR("Check Door")); break;
- // case STATUS_LINE_LENGTH_EXCEEDED: // Supported on Grbl-Mega only.
- // printPgmString(PSTR("Line length exceeded")); break;
- case STATUS_TRAVEL_EXCEEDED:
- printPgmString(PSTR("Travel exceeded")); break;
- case STATUS_INVALID_JOG_COMMAND:
- printPgmString(PSTR("Invalid jog command")); break;
- // Common g-code parser errors.
- case STATUS_GCODE_UNSUPPORTED_COMMAND:
- printPgmString(PSTR("Unsupported command")); break;
- case STATUS_GCODE_MODAL_GROUP_VIOLATION:
- printPgmString(PSTR("Modal group violation")); break;
- case STATUS_GCODE_UNDEFINED_FEED_RATE:
- printPgmString(PSTR("Undefined feed rate")); break;
- default:
- // Remaining g-code parser errors with error codes
- printPgmString(PSTR("Invalid gcode ID:"));
- print_uint8_base10(status_code); // Print error code for user reference
- }
- #else
- printPgmString(PSTR("error:"));
- print_uint8_base10(status_code);
- #endif
+ printPgmString(PSTR("error:"));
+ print_uint8_base10(status_code);
report_util_line_feed();
}
}
// Prints alarm messages.
-void report_alarm_message(int8_t alarm_code)
+void report_alarm_message(uint8_t alarm_code)
{
- #ifdef USE_CLASSIC_GRBL_INTERFACE
- printPgmString(PSTR("ALARM: "));
- switch (alarm_code) {
- case ALARM_HARD_LIMIT_ERROR:
- printPgmString(PSTR("Hard limit")); break;
- case ALARM_SOFT_LIMIT_ERROR:
- printPgmString(PSTR("Soft limit")); break;
- case ALARM_ABORT_CYCLE:
- printPgmString(PSTR("Abort during cycle")); break;
- case ALARM_PROBE_FAIL_INITIAL:
- case ALARM_PROBE_FAIL_CONTACT:
- printPgmString(PSTR("Probe fail")); break;
- case ALARM_HOMING_FAIL_RESET:
- case ALARM_HOMING_FAIL_DOOR:
- case ALARM_HOMING_FAIL_PULLOFF:
- case ALARM_HOMING_FAIL_APPROACH:
- printPgmString(PSTR("Homing fail")); break;
- }
- #else
- printPgmString(PSTR("ALARM:"));
- print_uint8_base10(alarm_code);
- #endif
+ printPgmString(PSTR("ALARM:"));
+ print_uint8_base10(alarm_code);
report_util_line_feed();
delay_ms(500); // Force delay to ensure message clears serial write buffer.
}
@@ -211,11 +136,7 @@ void report_alarm_message(int8_t alarm_code)
// is installed, the message number codes are less than zero.
void report_feedback_message(uint8_t message_code)
{
- #ifdef USE_CLASSIC_GRBL_INTERFACE
- serial_write('[');
- #else
- printPgmString(PSTR("[MSG:"));
- #endif
+ printPgmString(PSTR("[MSG:"));
switch(message_code) {
case MESSAGE_CRITICAL_EVENT:
printPgmString(PSTR("Reset to continue")); break;
@@ -252,26 +173,7 @@ void report_init_message()
// Grbl help message
void report_grbl_help() {
- #ifdef USE_CLASSIC_GRBL_INTERFACE
- printPgmString(PSTR("$$ (view Grbl settings)\r\n"
- "$# (view # parameters)\r\n"
- "$G (view parser state)\r\n"
- "$I (view build info)\r\n"
- "$N (view startup blocks)\r\n"
- "$x=value (save Grbl setting)\r\n"
- "$Nx=line (save startup block)\r\n"
- "$J=line (jog)\r\n"
- "$SLP (sleep mode)\r\n"
- "$C (check gcode mode)\r\n"
- "$X (kill alarm lock)\r\n"
- "$H (run homing cycle)\r\n"
- "~ (cycle start)\r\n"
- "! (feed hold)\r\n"
- "? (current status)\r\n"
- "ctrl-x (reset Grbl)\r\n"));
- #else
- printPgmString(PSTR("[HLP:$$ $# $G $I $N $x=val $Nx=line $J=line $SLP $C $X $H ~ ! ? ctrl-x]\r\n"));
- #endif
+ printPgmString(PSTR("[HLP:$$ $# $G $I $N $x=val $Nx=line $J=line $SLP $C $X $H ~ ! ? ctrl-x]\r\n"));
}
@@ -279,107 +181,46 @@ void report_grbl_help() {
// NOTE: The numbering scheme here must correlate to storing in settings.c
void report_grbl_settings() {
// Print Grbl settings.
- #ifdef USE_CLASSIC_GRBL_INTERFACE
- printPgmString(PSTR("$0=")); print_uint8_base10(settings.pulse_microseconds);
- printPgmString(PSTR(" (step pulse, usec)\r\n$1=")); print_uint8_base10(settings.stepper_idle_lock_time);
- printPgmString(PSTR(" (step idle delay, msec)\r\n$2=")); print_uint8_base10(settings.step_invert_mask);
- printPgmString(PSTR(" (step port invert mask)\r\n$3=")); print_uint8_base10(settings.dir_invert_mask);
- printPgmString(PSTR(" (dir port invert mask)\r\n$4=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE));
- printPgmString(PSTR(" (step enable invert, bool)\r\n$5=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS));
- printPgmString(PSTR(" (limit pins invert, bool)\r\n$6=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_INVERT_PROBE_PIN));
- printPgmString(PSTR(" (probe pin invert, bool)\r\n$10=")); print_uint8_base10(settings.status_report_mask);
- printPgmString(PSTR(" (status report mask)\r\n$11=")); printFloat(settings.junction_deviation,N_DECIMAL_SETTINGVALUE);
- printPgmString(PSTR(" (junction deviation, mm)\r\n$12=")); printFloat(settings.arc_tolerance,N_DECIMAL_SETTINGVALUE);
- printPgmString(PSTR(" (arc tolerance, mm)\r\n$13=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_REPORT_INCHES));
- printPgmString(PSTR(" (report inches, bool)\r\n$20=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE));
- printPgmString(PSTR(" (soft limits, bool)\r\n$21=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE));
- printPgmString(PSTR(" (hard limits, bool)\r\n$22=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE));
- printPgmString(PSTR(" (homing cycle, bool)\r\n$23=")); print_uint8_base10(settings.homing_dir_mask);
- printPgmString(PSTR(" (homing dir invert mask)\r\n$24=")); printFloat(settings.homing_feed_rate,N_DECIMAL_SETTINGVALUE);
- printPgmString(PSTR(" (homing feed, mm/min)\r\n$25=")); printFloat(settings.homing_seek_rate,N_DECIMAL_SETTINGVALUE);
- printPgmString(PSTR(" (homing seek, mm/min)\r\n$26=")); print_uint8_base10(settings.homing_debounce_delay);
- printPgmString(PSTR(" (homing debounce, msec)\r\n$27=")); printFloat(settings.homing_pulloff,N_DECIMAL_SETTINGVALUE);
- printPgmString(PSTR(" (homing pull-off, mm)\r\n$30=")); printFloat(settings.rpm_max,N_DECIMAL_RPMVALUE);
- printPgmString(PSTR(" (rpm max)\r\n$31=")); printFloat(settings.rpm_min,N_DECIMAL_RPMVALUE);
- #ifdef VARIABLE_SPINDLE
- printPgmString(PSTR(" (rpm min)\r\n$32=")); print_uint8_base10(bit_istrue(settings.flags,BITFLAG_LASER_MODE));
- printPgmString(PSTR(" (laser mode, bool)\r\n"));
- #else
- printPgmString(PSTR(" (rpm min)\r\n$32=0 (laser mode, bool)\r\n"));
- #endif
- // Print axis settings
- uint8_t idx, set_idx;
- uint8_t val = AXIS_SETTINGS_START_VAL;
- for (set_idx=0; set_idx= MOTION_MODE_PROBE_TOWARD) {
printPgmString(PSTR("38."));
print_uint8_base10(gc_state.modal.motion - (MOTION_MODE_PROBE_TOWARD-2));
@@ -481,14 +318,22 @@ void report_gcode_modes()
report_util_gcode_modes_M();
#ifdef ENABLE_M7
if (gc_state.modal.coolant) { // Note: Multiple coolant states may be active at the same time.
- if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_MIST) { serial_write('7'); }
- if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_FLOOD) { serial_write('8'); }
- } else { serial_write('9'); }
+ if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_MIST) { report_util_gcode_modes_M(); serial_write('7'); }
+ if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_FLOOD) { report_util_gcode_modes_M(); serial_write('8'); }
+ } else { report_util_gcode_modes_M(); serial_write('9'); }
#else
+ report_util_gcode_modes_M();
if (gc_state.modal.coolant) { serial_write('8'); }
else { serial_write('9'); }
#endif
+ #ifdef ENABLE_PARKING_OVERRIDE_CONTROL
+ if (sys.override_ctrl == OVERRIDE_PARKING_MOTION) {
+ report_util_gcode_modes_M();
+ print_uint8_base10(56);
+ }
+ #endif
+
printPgmString(PSTR(" T"));
print_uint8_base10(gc_state.tool);
@@ -515,81 +360,87 @@ void report_startup_line(uint8_t n, char *line)
void report_execute_startup_message(char *line, uint8_t status_code)
{
- #ifdef USE_CLASSIC_GRBL_INTERFACE
- printString(line);
- report_status_message(status_code);
- #else
- serial_write('>');
- printString(line);
- serial_write(':');
- report_status_message(status_code);
- #endif
+ serial_write('>');
+ printString(line);
+ serial_write(':');
+ report_status_message(status_code);
}
// Prints build info line
void report_build_info(char *line)
{
- #ifdef USE_CLASSIC_GRBL_INTERFACE
- printPgmString(PSTR("[" GRBL_VERSION "." GRBL_VERSION_BUILD ":"));
- printString(line);
- #else
- printPgmString(PSTR("[VER:" GRBL_VERSION "." GRBL_VERSION_BUILD ":"));
- printString(line);
- report_util_feedback_line_feed();
- printPgmString(PSTR("[OPT:")); // Generate compile-time build option list
- #ifdef VARIABLE_SPINDLE
- serial_write('V');
- #endif
- #ifdef USE_LINE_NUMBERS
- serial_write('N');
- #endif
- #ifdef ENABLE_M7
- serial_write('M');
- #endif
- #ifdef COREXY
- serial_write('C');
- #endif
- #ifdef PARKING_ENABLE
- serial_write('P');
- #endif
- #ifdef HOMING_FORCE_SET_ORIGIN
- serial_write('Z');
- #endif
- #ifdef HOMING_SINGLE_AXIS_COMMANDS
- serial_write('H');
- #endif
- #ifdef LIMITS_TWO_SWITCHES_ON_AXES
- serial_write('L');
- #endif
- #ifdef ALLOW_FEED_OVERRIDE_DURING_PROBE_CYCLES
- serial_write('A');
- #endif
- #ifdef USE_CLASSIC_GRBL_INTERFACE
- serial_write('R');
- #endif
- #ifndef ENABLE_RESTORE_EEPROM_WIPE_ALL // NOTE: Shown when disabled.
- serial_write('*');
- #endif
- #ifndef ENABLE_RESTORE_EEPROM_DEFAULT_SETTINGS // NOTE: Shown when disabled.
- serial_write('$');
- #endif
- #ifndef ENABLE_RESTORE_EEPROM_CLEAR_PARAMETERS // NOTE: Shown when disabled.
- serial_write('#');
- #endif
- #ifndef ENABLE_BUILD_INFO_WRITE_COMMAND // NOTE: Shown when disabled.
- serial_write('I');
- #endif
- #ifndef FORCE_BUFFER_SYNC_DURING_EEPROM_WRITE // NOTE: Shown when disabled.
- serial_write('E');
- #endif
- #ifndef FORCE_BUFFER_SYNC_DURING_WCO_CHANGE // NOTE: Shown when disabled.
- serial_write('W');
- #endif
- // NOTE: Compiled values, like override increments/max/min values, may be added at some point later.
- // These will likely have a comma delimiter to separate them.
- #endif
-
+ printPgmString(PSTR("[VER:" GRBL_VERSION "." GRBL_VERSION_BUILD ":"));
+ printString(line);
report_util_feedback_line_feed();
+ printPgmString(PSTR("[OPT:")); // Generate compile-time build option list
+ #ifdef VARIABLE_SPINDLE
+ serial_write('V');
+ #endif
+ #ifdef USE_LINE_NUMBERS
+ serial_write('N');
+ #endif
+ #ifdef ENABLE_M7
+ serial_write('M');
+ #endif
+ #ifdef COREXY
+ serial_write('C');
+ #endif
+ #ifdef PARKING_ENABLE
+ serial_write('P');
+ #endif
+ #ifdef HOMING_FORCE_SET_ORIGIN
+ serial_write('Z');
+ #endif
+ #ifdef HOMING_SINGLE_AXIS_COMMANDS
+ serial_write('H');
+ #endif
+ #ifdef LIMITS_TWO_SWITCHES_ON_AXES
+ serial_write('T');
+ #endif
+ #ifdef ALLOW_FEED_OVERRIDE_DURING_PROBE_CYCLES
+ serial_write('A');
+ #endif
+ #ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
+ serial_write('D');
+ #endif
+ #ifdef SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED
+ serial_write('0');
+ #endif
+ #ifdef ENABLE_SOFTWARE_DEBOUNCE
+ serial_write('S');
+ #endif
+ #ifdef ENABLE_PARKING_OVERRIDE_CONTROL
+ serial_write('R');
+ #endif
+ #ifndef ENABLE_RESTORE_EEPROM_WIPE_ALL // NOTE: Shown when disabled.
+ serial_write('*');
+ #endif
+ #ifndef ENABLE_RESTORE_EEPROM_DEFAULT_SETTINGS // NOTE: Shown when disabled.
+ serial_write('$');
+ #endif
+ #ifndef ENABLE_RESTORE_EEPROM_CLEAR_PARAMETERS // NOTE: Shown when disabled.
+ serial_write('#');
+ #endif
+ #ifndef ENABLE_BUILD_INFO_WRITE_COMMAND // NOTE: Shown when disabled.
+ serial_write('I');
+ #endif
+ #ifndef FORCE_BUFFER_SYNC_DURING_EEPROM_WRITE // NOTE: Shown when disabled.
+ serial_write('E');
+ #endif
+ #ifndef FORCE_BUFFER_SYNC_DURING_WCO_CHANGE // NOTE: Shown when disabled.
+ serial_write('W');
+ #endif
+ #ifndef HOMING_INIT_LOCK
+ serial_write('L');
+ #endif
+
+ // NOTE: Compiled values, like override increments/max/min values, may be added at some point later.
+ serial_write(',');
+ print_uint8_base10(BLOCK_BUFFER_SIZE - 1);
+ serial_write(',');
+ print_uint8_base10(RX_BUFFER_SIZE);
+
+ report_util_feedback_line_feed();
}
@@ -609,128 +460,163 @@ void report_echo_line_received(char *line)
// especially during g-code programs with fast, short line segments and high frequency reports (5-20Hz).
void report_realtime_status()
{
- #ifdef USE_CLASSIC_GRBL_INTERFACE
-
- uint8_t idx;
- int32_t current_position[N_AXIS]; // Copy current state of the system position variable
- memcpy(current_position,sys_position,sizeof(sys_position));
- float print_position[N_AXIS];
-
- // Report current machine state
- switch (sys.state) {
- case STATE_IDLE: printPgmString(PSTR("line_number;
+ if (ln > 0) {
+ printPgmString(PSTR("|Ln:"));
+ printInteger(ln);
}
+ }
+#endif
+#endif
+
+ // Report realtime feed speed
+#ifdef REPORT_FIELD_CURRENT_FEED_SPEED
+#ifdef VARIABLE_SPINDLE
+ printPgmString(PSTR("|FS:"));
+ printFloat_RateValue(st_get_realtime_rate());
+ serial_write(',');
+ printFloat(sys.spindle_speed, N_DECIMAL_RPMVALUE);
+#else
+ printPgmString(PSTR("|F:"));
+ printFloat_RateValue(st_get_realtime_rate());
+#endif
+#endif
- // Returns the number of active blocks are in the planner buffer.
- if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_PLANNER_BUFFER)) {
- printPgmString(PSTR(",Buf:"));
- print_uint8_base10(plan_get_block_buffer_count());
+#ifdef REPORT_FIELD_PIN_STATE
+ uint8_t lim_pin_state = limits_get_state();
+ uint8_t ctrl_pin_state = system_control_get_state();
+ uint8_t prb_pin_state = probe_get_state();
+ if (lim_pin_state | ctrl_pin_state | prb_pin_state) {
+ printPgmString(PSTR("|Pn:"));
+ if (prb_pin_state) { serial_write('P'); }
+ if (lim_pin_state) {
+ if (bit_istrue(lim_pin_state, bit(X_AXIS))) { serial_write('X'); }
+ if (bit_istrue(lim_pin_state, bit(Y_AXIS))) { serial_write('Y'); }
+ if (bit_istrue(lim_pin_state, bit(Z_AXIS))) { serial_write('Z'); }
}
+ if (ctrl_pin_state) {
+#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
+ if (bit_istrue(ctrl_pin_state, CONTROL_PIN_INDEX_SAFETY_DOOR)) { serial_write('D'); }
+#endif
+ if (bit_istrue(ctrl_pin_state, CONTROL_PIN_INDEX_RESET)) { serial_write('R'); }
+ if (bit_istrue(ctrl_pin_state, CONTROL_PIN_INDEX_FEED_HOLD)) { serial_write('H'); }
+ if (bit_istrue(ctrl_pin_state, CONTROL_PIN_INDEX_CYCLE_START)) { serial_write('S'); }
+ }
+ }
+#endif
- // Report serial read buffer status
- if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_SERIAL_RX)) {
- printPgmString(PSTR(",RX:"));
- print_uint8_base10(serial_get_rx_buffer_count());
+#ifdef REPORT_FIELD_WORK_COORD_OFFSET
+ if (sys.report_wco_counter > 0) { sys.report_wco_counter--; }
+ else {
+ if (sys.state & (STATE_HOMING | STATE_CYCLE | STATE_HOLD | STATE_JOG | STATE_SAFETY_DOOR)) {
+ sys.report_wco_counter = (REPORT_WCO_REFRESH_BUSY_COUNT - 1); // Reset counter for slow refresh
}
+ else { sys.report_wco_counter = (REPORT_WCO_REFRESH_IDLE_COUNT - 1); }
+ if (sys.report_ovr_counter == 0) { sys.report_ovr_counter = 1; } // Set override on next report.
+ printPgmString(PSTR("|WCO:"));
+ report_util_axis_values(wco);
+ }
+#endif
- #ifdef USE_LINE_NUMBERS
- // Report current line number
- printPgmString(PSTR(",Ln:"));
- int32_t ln=0;
- plan_block_t * pb = plan_get_current_block();
- if(pb != NULL) {
- ln = pb->line_number;
- }
- printInteger(ln);
- #endif
-
- #ifdef REPORT_REALTIME_RATE
- // Report realtime rate
- printPgmString(PSTR(",F:"));
- printFloat_RateValue(st_get_realtime_rate());
- #endif
-
- #ifdef REPORT_ALL_PIN_STATES
- if (bit_istrue(settings.status_report_mask,
- ( BITFLAG_RT_STATUS_LIMIT_PINS| BITFLAG_RT_STATUS_PROBE_PIN | BITFLAG_RT_STATUS_CONTROL_PINS ))) {
- printPgmString(PSTR(",Pin:"));
- if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_LIMIT_PINS)) {
- print_uint8_base2_ndigit(limits_get_state(),N_AXIS);
- }
- printPgmString(PSTR("|"));
- if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_PROBE_PIN)) {
- if (probe_get_state()) { printPgmString(PSTR("1")); }
- else { printPgmString(PSTR("0")); }
- }
- printPgmString(PSTR("|"));
- if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_CONTROL_PINS)) {
- print_uint8_base2_ndigit(system_control_get_state(),N_CONTROL_PIN);
- }
- }
- #else
- if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_LIMIT_PINS)) {
- printPgmString(PSTR(",Lim:"));
- print_uint8_base2_ndigit(limits_get_state(),N_AXIS);
+ #ifdef REPORT_FIELD_OVERRIDES
+ if (sys.report_ovr_counter > 0) { sys.report_ovr_counter--; }
+ else {
+ if (sys.state & (STATE_HOMING | STATE_CYCLE | STATE_HOLD | STATE_JOG | STATE_SAFETY_DOOR)) {
+ sys.report_ovr_counter = (REPORT_OVR_REFRESH_BUSY_COUNT - 1); // Reset counter for slow refresh
}
- #endif
-
- if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_OVERRIDES)) {
- printPgmString(PSTR(",Ov:"));
+ else { sys.report_ovr_counter = (REPORT_OVR_REFRESH_IDLE_COUNT - 1); }
+ printPgmString(PSTR("|Ov:"));
print_uint8_base10(sys.f_override);
serial_write(',');
print_uint8_base10(sys.r_override);
serial_write(',');
print_uint8_base10(sys.spindle_speed_ovr);
-
+
uint8_t sp_state = spindle_get_state();
- uint8_t cl_state = coolant_get_state();
- if (sp_state | cl_state) {
- printPgmString(PSTR(",A:"));
+ uint8_t cl_state = coolant_get_state();
+ if (sp_state || cl_state) {
+ printPgmString(PSTR("|A:"));
if (sp_state) { // != SPINDLE_STATE_DISABLE
#ifdef VARIABLE_SPINDLE
#ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
@@ -748,189 +634,12 @@ void report_realtime_status()
#ifdef ENABLE_M7
if (cl_state & COOLANT_STATE_MIST) { serial_write('M'); }
#endif
- }
- }
-
- printPgmString(PSTR(">\r\n"));
-
- #else
-
- uint8_t idx;
- int32_t current_position[N_AXIS]; // Copy current state of the system position variable
- memcpy(current_position,sys_position,sizeof(sys_position));
- float print_position[N_AXIS];
- system_convert_array_steps_to_mpos(print_position,current_position);
-
- // Report current machine state and sub-states
- serial_write('<');
- switch (sys.state) {
- case STATE_IDLE: printPgmString(PSTR("Idle")); break;
- case STATE_CYCLE: printPgmString(PSTR("Run")); break;
- case STATE_HOLD:
- if (!(sys.suspend & SUSPEND_JOG_CANCEL)) {
- printPgmString(PSTR("Hold:"));
- if (sys.suspend & SUSPEND_HOLD_COMPLETE) { serial_write('0'); } // Ready to resume
- else { serial_write('1'); } // Actively holding
- break;
- } // Continues to print jog state during jog cancel.
- case STATE_JOG: printPgmString(PSTR("Jog")); break;
- case STATE_HOMING: printPgmString(PSTR("Home")); break;
- case STATE_ALARM: printPgmString(PSTR("Alarm")); break;
- case STATE_CHECK_MODE: printPgmString(PSTR("Check")); break;
- case STATE_SAFETY_DOOR:
- printPgmString(PSTR("Door:"));
- if (sys.suspend & SUSPEND_INITIATE_RESTORE) {
- serial_write('3'); // Restoring
- } else {
- if (sys.suspend & SUSPEND_RETRACT_COMPLETE) {
- if (sys.suspend & SUSPEND_SAFETY_DOOR_AJAR) {
- serial_write('1'); // Door ajar
- } else {
- serial_write('0');
- } // Door closed and ready to resume
- } else {
- serial_write('2'); // Retracting
- }
- }
- break;
- case STATE_SLEEP: printPgmString(PSTR("Sleep")); break;
- }
-
- float wco[N_AXIS];
- if (bit_isfalse(settings.status_report_mask,BITFLAG_RT_STATUS_POSITION_TYPE) ||
- (sys.report_wco_counter == 0) ) {
- for (idx=0; idx< N_AXIS; idx++) {
- // Apply work coordinate offsets and tool length offset to current position.
- wco[idx] = gc_state.coord_system[idx]+gc_state.coord_offset[idx];
- if (idx == TOOL_LENGTH_OFFSET_AXIS) { wco[idx] += gc_state.tool_length_offset; }
- if (bit_isfalse(settings.status_report_mask,BITFLAG_RT_STATUS_POSITION_TYPE)) {
- print_position[idx] -= wco[idx];
- }
}
}
-
- // Report machine position
- if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_POSITION_TYPE)) {
- printPgmString(PSTR("|MPos:"));
- } else {
- printPgmString(PSTR("|WPos:"));
- }
- report_util_axis_values(print_position);
-
- // Returns planner and serial read buffer states.
- #ifdef REPORT_FIELD_BUFFER_STATE
- if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_BUFFER_STATE)) {
- printPgmString(PSTR("|Bf:"));
- print_uint8_base10(plan_get_block_buffer_available());
- serial_write(',');
- print_uint8_base10(serial_get_rx_buffer_available());
- }
- #endif
-
- #ifdef USE_LINE_NUMBERS
- #ifdef REPORT_FIELD_LINE_NUMBERS
- // Report current line number
- plan_block_t * cur_block = plan_get_current_block();
- if (cur_block != NULL) {
- uint32_t ln = cur_block->line_number;
- if (ln > 0) {
- printPgmString(PSTR("|Ln:"));
- printInteger(ln);
- }
- }
- #endif
- #endif
-
- // Report realtime feed speed
- #ifdef REPORT_FIELD_CURRENT_FEED_SPEED
- #ifdef VARIABLE_SPINDLE
- printPgmString(PSTR("|FS:"));
- printFloat_RateValue(st_get_realtime_rate());
- serial_write(',');
- printFloat(sys.spindle_speed,N_DECIMAL_RPMVALUE);
- #else
- printPgmString(PSTR("|F:"));
- printFloat_RateValue(st_get_realtime_rate());
- #endif
- #endif
-
- #ifdef REPORT_FIELD_PIN_STATE
- uint8_t lim_pin_state = limits_get_state();
- uint8_t ctrl_pin_state = system_control_get_state();
- uint8_t prb_pin_state = probe_get_state();
- if (lim_pin_state | ctrl_pin_state | prb_pin_state) {
- printPgmString(PSTR("|Pn:"));
- if (prb_pin_state) { serial_write('P'); }
- if (lim_pin_state) {
- if (bit_istrue(lim_pin_state,bit(X_AXIS))) { serial_write('X'); }
- if (bit_istrue(lim_pin_state,bit(Y_AXIS))) { serial_write('Y'); }
- if (bit_istrue(lim_pin_state,bit(Z_AXIS))) { serial_write('Z'); }
- }
- if (ctrl_pin_state) {
- #ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
- if (bit_istrue(ctrl_pin_state,CONTROL_PIN_INDEX_SAFETY_DOOR)) { serial_write('D'); }
- #endif
- if (bit_istrue(ctrl_pin_state,CONTROL_PIN_INDEX_RESET)) { serial_write('R'); }
- if (bit_istrue(ctrl_pin_state,CONTROL_PIN_INDEX_FEED_HOLD)) { serial_write('H'); }
- if (bit_istrue(ctrl_pin_state,CONTROL_PIN_INDEX_CYCLE_START)) { serial_write('S'); }
- }
- }
- #endif
-
- #ifdef REPORT_FIELD_WORK_COORD_OFFSET
- if (sys.report_wco_counter > 0) { sys.report_wco_counter--; }
- else {
- if (sys.state & (STATE_HOMING | STATE_CYCLE | STATE_HOLD | STATE_JOG | STATE_SAFETY_DOOR)) {
- sys.report_wco_counter = (REPORT_WCO_REFRESH_BUSY_COUNT-1); // Reset counter for slow refresh
- } else { sys.report_wco_counter = (REPORT_WCO_REFRESH_IDLE_COUNT-1); }
- if (sys.report_ovr_counter == 0) { sys.report_ovr_counter = 1; } // Set override on next report.
- printPgmString(PSTR("|WCO:"));
- report_util_axis_values(wco);
- }
- #endif
-
- #ifdef REPORT_FIELD_OVERRIDES
- if (sys.report_ovr_counter > 0) { sys.report_ovr_counter--; }
- else {
- if (sys.state & (STATE_HOMING | STATE_CYCLE | STATE_HOLD | STATE_JOG | STATE_SAFETY_DOOR)) {
- sys.report_ovr_counter = (REPORT_OVR_REFRESH_BUSY_COUNT-1); // Reset counter for slow refresh
- } else { sys.report_ovr_counter = (REPORT_OVR_REFRESH_IDLE_COUNT-1); }
- printPgmString(PSTR("|Ov:"));
- print_uint8_base10(sys.f_override);
- serial_write(',');
- print_uint8_base10(sys.r_override);
- serial_write(',');
- print_uint8_base10(sys.spindle_speed_ovr);
-
- uint8_t sp_state = spindle_get_state();
- uint8_t cl_state = coolant_get_state();
- if (sp_state || cl_state) {
- printPgmString(PSTR("|A:"));
- if (sp_state) { // != SPINDLE_STATE_DISABLE
- #ifdef VARIABLE_SPINDLE
- #ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
- serial_write('S'); // CW
- #else
- if (sp_state == SPINDLE_STATE_CW) { serial_write('S'); } // CW
- else { serial_write('C'); } // CCW
- #endif
- #else
- if (sp_state & SPINDLE_STATE_CW) { serial_write('S'); } // CW
- else { serial_write('C'); } // CCW
- #endif
- }
- if (cl_state & COOLANT_STATE_FLOOD) { serial_write('F'); }
- #ifdef ENABLE_M7
- if (cl_state & COOLANT_STATE_MIST) { serial_write('M'); }
- #endif
- }
- }
- #endif
-
- serial_write('>');
- report_util_line_feed();
-
#endif
+
+ serial_write('>');
+ report_util_line_feed();
}
diff --git a/grbl/report.h b/grbl/report.h
index 6488ed1e..f1480026 100644
--- a/grbl/report.h
+++ b/grbl/report.h
@@ -38,6 +38,7 @@
#define STATUS_LINE_LENGTH_EXCEEDED 14
#define STATUS_TRAVEL_EXCEEDED 15
#define STATUS_INVALID_JOG_COMMAND 16
+#define STATUS_SETTING_DISABLED_LASER 17
#define STATUS_GCODE_UNSUPPORTED_COMMAND 20
#define STATUS_GCODE_MODAL_GROUP_VIOLATION 21
@@ -57,6 +58,7 @@
#define STATUS_GCODE_NO_OFFSETS_IN_PLANE 35
#define STATUS_GCODE_UNUSED_WORDS 36
#define STATUS_GCODE_G43_DYNAMIC_AXIS_ERROR 37
+#define STATUS_GCODE_MAX_VALUE_EXCEEDED 38
// Define Grbl alarm codes. Valid values (1-255). 0 is reserved.
#define ALARM_HARD_LIMIT_ERROR EXEC_ALARM_HARD_LIMIT
@@ -86,7 +88,7 @@
void report_status_message(uint8_t status_code);
// Prints system alarm messages.
-void report_alarm_message(int8_t alarm_code);
+void report_alarm_message(uint8_t alarm_code);
// Prints miscellaneous feedback messages.
void report_feedback_message(uint8_t message_code);
diff --git a/grbl/serial.c b/grbl/serial.c
index cf5f35e2..b4e72a27 100644
--- a/grbl/serial.c
+++ b/grbl/serial.c
@@ -20,9 +20,35 @@
*/
#include "grbl.h"
-
+#ifdef WIN32
+#include
+#include
+#include
+CRITICAL_SECTION CriticalSection;
+//#define LOCAL_ECHO
+
+HANDLE hSerial = INVALID_HANDLE_VALUE;
+void RecvthreadFunction( void *);
+void SendthreadFunction( void *);
+
+#endif
+#ifdef STM32F103C8
+#include "stm32f10x.h"
+#include "core_cm3.h"
+#ifndef USEUSB
+#include "stm32f10x_usart.h"
+#else
+#include "usb_regs.h"
+#endif
+#endif
+
+#if !defined(STM32F103C8)
#define RX_RING_BUFFER (RX_BUFFER_SIZE+1)
#define TX_RING_BUFFER (TX_BUFFER_SIZE+1)
+#else
+#define RX_RING_BUFFER (RX_BUFFER_SIZE)
+#define TX_RING_BUFFER (TX_BUFFER_SIZE)
+#endif
uint8_t serial_rx_buffer[RX_RING_BUFFER];
uint8_t serial_rx_buffer_head = 0;
@@ -64,7 +90,8 @@ uint8_t serial_get_tx_buffer_count()
void serial_init()
{
- // Set baud rate
+#ifdef AVRTARGET
+ // Set baud rate
#if BAUD_RATE < 57600
uint16_t UBRR0_value = ((F_CPU / (8L * BAUD_RATE)) - 1)/2 ;
UCSR0A &= ~(1 << U2X0); // baud doubler off - Only needed on Uno XXX
@@ -79,30 +106,103 @@ void serial_init()
UCSR0B |= (1<SR & USART_FLAG_TXE)); //µÈ´ý·¢ËÍÍê³É
+ return;
+#endif
+#endif
if (next_head == TX_RING_BUFFER) { next_head = 0; }
// Wait until there is space in the buffer
while (next_head == serial_tx_buffer_tail) {
// TODO: Restructure st_prep_buffer() calls to be executed here during a long print.
if (sys_rt_exec_state & EXEC_RESET) { return; } // Only check for abort to avoid an endless loop.
+#ifdef WIN32
+ Sleep(1);
+#endif
}
// Store data and advance head
serial_tx_buffer[serial_tx_buffer_head] = data;
+
serial_tx_buffer_head = next_head;
+#ifdef AVRTARGET
// Enable Data Register Empty Interrupt to make sure tx-streaming is running
UCSR0B |= (1 << UDRIE0);
+#endif
}
-
+#ifdef AVRTARGET
// Data Register Empty Interrupt handler
ISR(SERIAL_UDRE)
{
@@ -120,7 +220,60 @@ ISR(SERIAL_UDRE)
// Turn off Data Register Empty Interrupt to stop tx-streaming if this concludes the transfer
if (tail == serial_tx_buffer_head) { UCSR0B &= ~(1 << UDRIE0); }
}
-
+#endif
+#ifdef WIN32
+void SendthreadFunction( void *pVoid)
+{
+ unsigned char szBuf[RX_RING_BUFFER + 1];
+
+ DWORD dwBytesWritten;
+ uint8_t nNextTai;
+ for (;;)
+ {
+ while (serial_tx_buffer_head == serial_tx_buffer_tail)
+ Sleep(1);
+ uint16_t USB_Tx_length;
+
+ if (serial_tx_buffer_head > serial_tx_buffer_tail)
+ USB_Tx_length = serial_tx_buffer_head - serial_tx_buffer_tail;
+ else
+ {
+ USB_Tx_length = RX_RING_BUFFER - serial_tx_buffer_tail;
+ if (USB_Tx_length == 0)
+ {
+ USB_Tx_length = serial_tx_buffer_head;
+ }
+ }
+ nNextTai = serial_tx_buffer_tail;
+
+ if (USB_Tx_length != 0)
+ {
+ if (hSerial != INVALID_HANDLE_VALUE)
+ {
+ WriteFile(hSerial, serial_tx_buffer + serial_tx_buffer_tail, USB_Tx_length, &dwBytesWritten, NULL);
+ nNextTai += (uint8_t)dwBytesWritten;
+#ifdef LOCAL_ECHO
+ memcpy(szBuf, &serial_tx_buffer[serial_tx_buffer_tail], dwBytesWritten);
+ szBuf[dwBytesWritten] = 0;
+ printf(szBuf);
+#endif
+ }
+ else
+ {
+ // fwrite(szBuf, 1, USB_Tx_length, stdout);
+ memcpy(szBuf, &serial_tx_buffer[serial_tx_buffer_tail], USB_Tx_length);
+ szBuf[USB_Tx_length] = 0;
+ printf(szBuf);
+ nNextTai += USB_Tx_length;
+ }
+ if (nNextTai == RX_RING_BUFFER)
+ nNextTai = 0;
+
+ serial_tx_buffer_tail = nNextTai;
+ }
+ }
+}
+#endif
// Fetches the first byte in the serial read buffer. Called by main program.
uint8_t serial_read()
@@ -139,12 +292,73 @@ uint8_t serial_read()
}
}
-
+#ifdef AVRTARGET
ISR(SERIAL_RX)
{
uint8_t data = UDR0;
uint8_t next_head;
+#endif
+#ifdef WIN32
+//#define WINLOG
+void RecvthreadFunction(void *pVoid )
+{
+ DWORD dwBytesRead;
+ uint8_t data;
+ uint8_t next_head;
+ for (;;)
+ {
+ if (hSerial != INVALID_HANDLE_VALUE)
+ {
+ if (ReadFile(hSerial, &data, 1, &dwBytesRead, NULL) && dwBytesRead == 1)
+ {
+ }
+ else
+ {
+#ifdef WIN32
+ Sleep(1);
+#endif
+ data = 0;
+ }
+ }
+ else
+ {
+ while (_kbhit() == 0)
+ ;
+ data = _getch();
+ }
+ if (data == 0)
+ continue;
+#endif
+#ifdef STM32F103C8
+#ifdef USEUSB
+void OnUsbDataRx(uint8_t* dataIn, uint8_t length)
+{
+ //lcd_write_char(*dataIn);
+ uint8_t next_head;
+ uint8_t data;
+
+ // Write data to buffer unless it is full.
+ while (length != 0)
+ {
+ data = *dataIn ++;
+#else
+/*----------------------------------------------------------------------------
+ USART1_IRQHandler
+ Handles USART1 global interrupt request.
+ *----------------------------------------------------------------------------*/
+void USART1_IRQHandler (void)
+{
+ volatile unsigned int IIR;
+ uint8_t data;
+ uint8_t next_head;
+
+ IIR = USART1->SR;
+ if (IIR & USART_FLAG_RXNE)
+ { // read interrupt
+ data = USART1->DR & 0x1FF;
+#endif
+#endif
// Pick off realtime command characters directly from the serial stream. These characters are
// not passed into the main buffer, but these set system state flag bits for realtime execution.
switch (data) {
@@ -195,9 +409,19 @@ ISR(SERIAL_RX)
}
}
}
+#ifdef WIN32
+ }
+#endif
+#ifdef STM32F103C8
+#ifndef USEUSB
+ USART1->SR &= ~USART_FLAG_RXNE; // clear interrupt
+#else
+ length--;
+#endif
+ }
+#endif
}
-
void serial_reset_read_buffer()
{
serial_rx_buffer_tail = serial_rx_buffer_head;
diff --git a/grbl/serial.h b/grbl/serial.h
index 5a3f7761..dd0b5a62 100644
--- a/grbl/serial.h
+++ b/grbl/serial.h
@@ -22,7 +22,7 @@
#ifndef serial_h
#define serial_h
-
+#ifdef AVRTARGET
#ifndef RX_BUFFER_SIZE
#define RX_BUFFER_SIZE 128
#endif
@@ -33,9 +33,20 @@
#define TX_BUFFER_SIZE 104
#endif
#endif
+#else
+#define RX_BUFFER_SIZE 254
+#ifndef WIN32
+#define TX_BUFFER_SIZE 128 // Do not try 256 it will not work for STM32.
+#else
+#define TX_BUFFER_SIZE 254
+#endif
+#endif
#define SERIAL_NO_DATA 0xff
+#ifdef WIN32
+void winserial_init(char *pPort);
+#endif
void serial_init();
diff --git a/grbl/settings.c b/grbl/settings.c
index c3e907cc..65f5371f 100644
--- a/grbl/settings.c
+++ b/grbl/settings.c
@@ -168,8 +168,10 @@ uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data)
uint32_t addr = coord_select*(sizeof(float)*N_AXIS+1) + EEPROM_ADDR_PARAMETERS;
if (!(memcpy_from_eeprom_with_checksum((char*)coord_data, addr, sizeof(float)*N_AXIS))) {
// Reset with default zero vector
- clear_vector_float(coord_data);
- settings_write_coord_data(coord_select,coord_data);
+ coord_data[X_AXIS] = 0.0f;
+ coord_data[Y_AXIS] = 0.0f;
+ coord_data[Z_AXIS] = 0.0f;
+ settings_write_coord_data(coord_select,coord_data);
return(false);
}
return(true);
@@ -194,7 +196,7 @@ uint8_t read_global_settings() {
// A helper method to set settings from command line
uint8_t settings_store_global_setting(uint8_t parameter, float value) {
- if (value < 0.0) { return(STATUS_NEGATIVE_VALUE); }
+ if (value < 0.0f) { return(STATUS_NEGATIVE_VALUE); }
if (parameter >= AXIS_SETTINGS_START_VAL) {
// Store axis configuration. Axis numbering sequence set by AXIS_SETTING defines.
// NOTE: Ensure the setting index corresponds to the report.c settings printout.
@@ -206,13 +208,13 @@ uint8_t settings_store_global_setting(uint8_t parameter, float value) {
switch (set_idx) {
case 0:
#ifdef MAX_STEP_RATE_HZ
- if (value*settings.max_rate[parameter] > (MAX_STEP_RATE_HZ*60.0)) { return(STATUS_MAX_STEP_RATE_EXCEEDED); }
+ if (value*settings.max_rate[parameter] >(MAX_STEP_RATE_HZ*60.0f)) { return(STATUS_MAX_STEP_RATE_EXCEEDED); }
#endif
settings.steps_per_mm[parameter] = value;
break;
case 1:
#ifdef MAX_STEP_RATE_HZ
- if (value*settings.steps_per_mm[parameter] > (MAX_STEP_RATE_HZ*60.0)) { return(STATUS_MAX_STEP_RATE_EXCEEDED); }
+ if (value*settings.steps_per_mm[parameter] > (MAX_STEP_RATE_HZ*60.0f)) { return(STATUS_MAX_STEP_RATE_EXCEEDED); }
#endif
settings.max_rate[parameter] = value;
break;
@@ -229,7 +231,7 @@ uint8_t settings_store_global_setting(uint8_t parameter, float value) {
}
} else {
// Store non-axis Grbl settings
- uint8_t int_value = trunc(value);
+ uint8_t int_value = truncf(value);
switch(parameter) {
case 0:
if (int_value < 3) { return(STATUS_SETTING_STEP_PULSE_MIN); }
@@ -294,7 +296,7 @@ uint8_t settings_store_global_setting(uint8_t parameter, float value) {
if (int_value) { settings.flags |= BITFLAG_LASER_MODE; }
else { settings.flags &= ~BITFLAG_LASER_MODE; }
#else
- return(STATUS_SETTING_DISABLED);
+ return(STATUS_SETTING_DISABLED_LASER);
#endif
break;
default:
@@ -315,29 +317,3 @@ void settings_init() {
}
}
-
-// Returns step pin mask according to Grbl internal axis indexing.
-uint8_t get_step_pin_mask(uint8_t axis_idx)
-{
- if ( axis_idx == X_AXIS ) { return((1<CCR1 = pwm_value;
+#endif
+ #ifdef SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED
+ if (pwm_value == SPINDLE_PWM_OFF_VALUE) {
+ spindle_stop();
+ } else {
+ #ifdef AVRTARGET
+ SPINDLE_TCCRA_REGISTER |= (1<= settings.rpm_max) || (rpm >= settings.rpm_max)) {
- // No PWM range possible. Set simple on/off spindle control pin state.
- sys.spindle_speed = settings.rpm_max;
- pwm_value = SPINDLE_PWM_MAX_VALUE;
- } else if (rpm <= settings.rpm_min) {
- if (rpm == 0.0) { // S0 disables spindle
- sys.spindle_speed = 0.0;
- pwm_value = SPINDLE_PWM_OFF_VALUE;
- } else { // Set minimum PWM output
- sys.spindle_speed = settings.rpm_min;
- pwm_value = SPINDLE_PWM_MIN_VALUE;
- }
- } else {
- // Compute intermediate PWM value with linear spindle speed model.
- // NOTE: A nonlinear model could be installed here, if required, but keep it VERY light-weight.
- sys.spindle_speed = rpm;
- pwm_value = floor((rpm-settings.rpm_min)*pwm_gradient) + SPINDLE_PWM_MIN_VALUE;
- }
- return(pwm_value);
- }
+ #ifdef ENABLE_PIECEWISE_LINEAR_SPINDLE
+ // Called by spindle_set_state() and step segment generator. Keep routine small and efficient.
+ SPINDLE_PWM_TYPE spindle_compute_pwm_value(float rpm) // 328p PWM register is 8-bit.
+ {
+ SPINDLE_PWM_TYPE pwm_value;
+ rpm *= (0.010*sys.spindle_speed_ovr); // Scale by spindle speed override value.
+ // Calculate PWM register value based on rpm max/min settings and programmed rpm.
+ if ((settings.rpm_min >= settings.rpm_max) || (rpm >= RPM_MAX)) {
+ rpm = RPM_MAX;
+ pwm_value = SPINDLE_PWM_MAX_VALUE;
+ }
+ else if (rpm <= RPM_MIN) {
+ if (rpm == 0.0) { // S0 disables spindle
+ pwm_value = SPINDLE_PWM_OFF_VALUE;
+ }
+ else {
+ rpm = RPM_MIN;
+ pwm_value = SPINDLE_PWM_MIN_VALUE;
+ }
+ }
+ else {
+ // Compute intermediate PWM value with linear spindle speed model via piecewise linear fit model.
+#if (N_PIECES > 3)
+ if (rpm > RPM_POINT34) {
+ pwm_value = floorf(RPM_LINE_A4*rpm - RPM_LINE_B4);
+ }
+ else
+#endif
+#if (N_PIECES > 2)
+ if (rpm > RPM_POINT23) {
+ pwm_value = floorf(RPM_LINE_A3*rpm - RPM_LINE_B3);
+ }
+ else
+#endif
+#if (N_PIECES > 1)
+ if (rpm > RPM_POINT12) {
+ pwm_value = floorf(RPM_LINE_A2*rpm - RPM_LINE_B2);
+ }
+ else
+#endif
+ {
+ pwm_value = floorf(RPM_LINE_A1*rpm - RPM_LINE_B1);
+ }
+ }
+ sys.spindle_speed = rpm;
+ return(pwm_value);
+ }
+ #else
+ // Called by spindle_set_state() and step segment generator. Keep routine small and efficient.
+ SPINDLE_PWM_TYPE spindle_compute_pwm_value(float rpm) // 328p PWM register is 8-bit.
+ {
+ SPINDLE_PWM_TYPE pwm_value;
+ rpm *= (0.010f*sys.spindle_speed_ovr); // Scale by spindle speed override value.
+ // Calculate PWM register value based on rpm max/min settings and programmed rpm.
+ if ((settings.rpm_min >= settings.rpm_max) || (rpm >= settings.rpm_max)) {
+ // No PWM range possible. Set simple on/off spindle control pin state.
+ sys.spindle_speed = settings.rpm_max;
+ pwm_value = SPINDLE_PWM_MAX_VALUE;
+ }
+ else if (rpm <= settings.rpm_min) {
+ if (rpm == 0.0f) { // S0 disables spindle
+ sys.spindle_speed = 0.0f;
+ pwm_value = SPINDLE_PWM_OFF_VALUE;
+ }
+ else { // Set minimum PWM output
+ sys.spindle_speed = settings.rpm_min;
+ pwm_value = SPINDLE_PWM_MIN_VALUE;
+ }
+ }
+ else {
+ // Compute intermediate PWM value with linear spindle speed model.
+ // NOTE: A nonlinear model could be installed here, if required, but keep it VERY light-weight.
+ sys.spindle_speed = rpm;
+ pwm_value = (SPINDLE_PWM_TYPE)floorf((rpm - settings.rpm_min)*pwm_gradient) + SPINDLE_PWM_MIN_VALUE;
+ }
+ return(pwm_value);
+ }
+ #endif
#endif
@@ -174,36 +326,37 @@ void spindle_stop()
if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm.
#ifdef VARIABLE_SPINDLE
- sys.spindle_speed = 0.0;
+ sys.spindle_speed = 0.0f;
#endif
spindle_stop();
} else {
-
#ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
if (state == SPINDLE_ENABLE_CW) {
- SPINDLE_DIRECTION_PORT &= ~(1<
+unsigned char PORTB = 0;
+unsigned char DDRD = 0;
+unsigned char DDRB = 0;
+unsigned char PORTD = 0;
+LARGE_INTEGER Win32Frequency;
+LONGLONG nTimer1Out = 0;
+LONGLONG nTimer0Out = 0;
+#endif
// Stores the planner block Bresenham algorithm execution data for the segments in the segment
@@ -97,9 +140,13 @@ typedef struct {
#endif
uint8_t execute_step; // Flags step execution for each interrupt.
+#ifndef WIN32
uint8_t step_pulse_time; // Step pulse reset time after step rise
- uint8_t step_outbits; // The next stepping-bits to be output
- uint8_t dir_outbits;
+#else
+ LONGLONG step_pulse_time;
+#endif
+ PORTPINDEF step_outbits; // The next stepping-bits to be output
+ PORTPINDEF dir_outbits;
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
uint32_t steps[N_AXIS];
#endif
@@ -117,8 +164,8 @@ static uint8_t segment_buffer_head;
static uint8_t segment_next_head;
// Step and direction port invert masks.
-static uint8_t step_port_invert_mask;
-static uint8_t dir_port_invert_mask;
+static PORTPINDEF step_port_invert_mask;
+static PORTPINDEF dir_port_invert_mask;
// Used to avoid ISR nesting of the "Stepper Driver Interrupt". Should never occur though.
static volatile uint8_t busy;
@@ -157,7 +204,7 @@ typedef struct {
#ifdef VARIABLE_SPINDLE
float inv_rate; // Used by PWM laser mode to speed up segment calculations.
- uint8_t current_spindle_pwm;
+ uint8_t current_spindle_pwm;
#endif
} st_prep_t;
static st_prep_t prep;
@@ -207,8 +254,14 @@ static st_prep_t prep;
void st_wake_up()
{
// Enable stepper drivers.
- if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) { STEPPERS_DISABLE_PORT |= (1<> 3);
#else // Normal operation
// Set step pulse time. Ad hoc computation from oscilloscope. Uses two's complement.
- st.step_pulse_time = -(((settings.pulse_microseconds-2)*TICKS_PER_MICROSECOND) >> 3);
+#ifdef AVRTARGET
+ st.step_pulse_time = -(((settings.pulse_microseconds - 2)*TICKS_PER_MICROSECOND) >> 3);
+#elif defined (WIN32)
+ st.step_pulse_time = (settings.pulse_microseconds)*TICKS_PER_MICROSECOND;
+#elif defined(STM32F103C8)
+ st.step_pulse_time = (settings.pulse_microseconds)*TICKS_PER_MICROSECOND;
+#endif
#endif
// Enable Stepper Driver Interrupt
+#ifdef AVRTARGET
TIMSK1 |= (1<ARR = st.step_pulse_time - 1;
+ TIM3->EGR = TIM_PSCReloadMode_Immediate;
+ TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
+
+ TIM2->ARR = st.exec_segment->cycles_per_tick - 1;
+ /* Set the Autoreload value */
+#ifndef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
+ TIM2->PSC = st.exec_segment->prescaler;
+#endif
+ TIM2->EGR = TIM_PSCReloadMode_Immediate;
+ NVIC_EnableIRQ(TIM2_IRQn);
+#endif
}
@@ -233,8 +310,17 @@ void st_wake_up()
void st_go_idle()
{
// Disable Stepper Driver Interrupt. Allow Stepper Port Reset Interrupt to finish, if active.
+#ifdef AVRTARGET
TIMSK1 &= ~(1<SR & 0x0001) != 0) // check interrupt source
+ {
+ TIM2->SR &= ~(1 << 0); // clear UIF flag
+ TIM2->CNT = 0;
+ }
+ else
+ {
+ return;
+ }
+#endif
+ if (busy) { return; } // The busy-flag is used to avoid reentering this interrupt
+#ifdef AVRTARGET
// Set the direction pins a couple of nanoseconds before we step the steppers
DIRECTION_PORT = (DIRECTION_PORT & ~DIRECTION_MASK) | (st.dir_outbits & DIRECTION_MASK);
+#endif
+#ifdef STM32F103C8
+ GPIO_Write(DIRECTION_PORT, (GPIO_ReadOutputData(DIRECTION_PORT) & ~DIRECTION_MASK) | (st.dir_outbits & DIRECTION_MASK));
+ TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
+#endif
// Then pulse the stepping pins
#ifdef STEP_PULSE_DELAY
st.step_bits = (STEP_PORT & ~STEP_MASK) | st.step_outbits; // Store out_bits to prevent overwriting.
#else // Normal operation
+#ifdef AVRTARGET
STEP_PORT = (STEP_PORT & ~STEP_MASK) | st.step_outbits;
+#endif
+#ifdef STM32F103C8
+ GPIO_Write(STEP_PORT, (GPIO_ReadOutputData(STEP_PORT) & ~STEP_MASK) | st.step_outbits);
+#endif
#endif
// Enable step pulse reset timer so that The Stepper Port Reset Interrupt can reset the signal after
// exactly settings.pulse_microseconds microseconds, independent of the main Timer1 prescaler.
+#ifdef AVRTARGET
TCNT0 = st.step_pulse_time; // Reload Timer0 counter
TCCR0B = (1<prescaler<cycles_per_tick;
+#endif
+#ifdef WIN32
+#ifndef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
+ nTimer1Out = st.exec_segment->cycles_per_tick * (st.exec_segment->prescaler + 1);
+#else
+ nTimer1Out = st.exec_segment->cycles_per_tick;
+#endif
+#endif
+#ifdef STM32F103C8
+ TIM2->ARR = st.exec_segment->cycles_per_tick - 1;
+ /* Set the Autoreload value */
+#ifndef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
+ TIM2->PSC = st.exec_segment->prescaler;
+#endif
+#endif
st.step_count = st.exec_segment->n_step; // NOTE: Can sometimes be zero when moving slow.
// If the new segment starts a new planner block, initialize stepper variables and counters.
// NOTE: When the segment data index changes, this indicates a new planner block.
@@ -364,7 +514,9 @@ ISR(TIMER1_COMPA_vect)
// Segment buffer empty. Shutdown.
st_go_idle();
// Ensure pwm is set properly upon completion of rate-controlled motion.
+ #ifdef VARIABLE_SPINDLE
if (st.exec_block->is_pwm_rate_adjusted) { spindle_set_speed(SPINDLE_PWM_OFF_VALUE); }
+ #endif
system_set_exec_state_flag(EXEC_CYCLE_STOP); // Flag main program for cycle end
return; // Nothing to do but exit.
}
@@ -419,7 +571,17 @@ ISR(TIMER1_COMPA_vect)
if (st.step_count == 0) {
// Segment is complete. Discard current segment and advance segment indexing.
st.exec_segment = NULL;
- if ( ++segment_buffer_tail == SEGMENT_BUFFER_SIZE) { segment_buffer_tail = 0; }
+#ifndef WIN32
+ uint8_t segment_tail_next = segment_buffer_tail + 1;
+ if (segment_tail_next == SEGMENT_BUFFER_SIZE)
+ segment_tail_next = 0;
+ segment_buffer_tail = segment_tail_next;
+#else
+ if ( ++segment_buffer_tail == SEGMENT_BUFFER_SIZE)
+ {
+ segment_buffer_tail = 0;
+ }
+#endif
}
st.step_outbits ^= step_port_invert_mask; // Apply step port invert mask
@@ -438,11 +600,33 @@ ISR(TIMER1_COMPA_vect)
// This interrupt is enabled by ISR_TIMER1_COMPAREA when it sets the motor port bits to execute
// a step. This ISR resets the motor port after a short period (settings.pulse_microseconds)
// completing one step cycle.
+#ifdef STM32F103C8
+void TIM3_IRQHandler(void)
+#endif
+#ifdef AVRTARGET
ISR(TIMER0_OVF_vect)
+#endif
+#ifdef WIN32
+void Timer0Proc()
+#endif
{
+#ifdef STM32F103C8
+ if ((TIM3->SR & 0x0001) != 0) // check interrupt source
+ {
+ TIM3->SR &= ~(1<<0); // clear UIF flag
+ TIM3->CNT = 0;
+ NVIC_DisableIRQ(TIM3_IRQn);
+ GPIO_Write(STEP_PORT, (GPIO_ReadOutputData(STEP_PORT) & ~STEP_MASK) | (step_port_invert_mask & STEP_MASK));
+ }
+#endif
+#ifdef AVRTARGET
// Reset stepping pins (leave the direction pins)
STEP_PORT = (STEP_PORT & ~STEP_MASK) | (step_port_invert_mask & STEP_MASK);
TCCR0B = 0; // Disable Timer0 to prevent re-entering this interrupt when it's not needed.
+#endif
+#ifdef WIN32
+ nTimer0Out = 0;
+#endif
}
#ifdef STEP_PULSE_DELAY
// This interrupt is used only when STEP_PULSE_DELAY is enabled. Here, the step pulse is
@@ -464,8 +648,8 @@ void st_generate_step_dir_invert_masks()
step_port_invert_mask = 0;
dir_port_invert_mask = 0;
for (idx=0; idxAPB1ENR |= RCC_APB1Periph_TIM2;
+ TIM_Configuration(TIM2, 1, 1, 1);
+ RCC->APB1ENR |= RCC_APB1Periph_TIM3;
+ TIM_Configuration(TIM3, 1, 1, 1);
+ NVIC_DisableIRQ(TIM3_IRQn);
+ NVIC_DisableIRQ(TIM2_IRQn);
+#endif
+#ifdef AVRTARGET
STEP_DDR |= STEP_MASK;
STEPPERS_DISABLE_DDR |= 1<direction_bits = pl_block->direction_bits;
uint8_t idx;
#ifndef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
- for (idx=0; idxsteps[idx] = pl_block->steps[idx]; }
- st_prep_block->step_event_count = pl_block->step_event_count;
+ for (idx=0; idxsteps[idx] = (pl_block->steps[idx] << 1); }
+ st_prep_block->step_event_count = (pl_block->step_event_count << 1);
#else
// With AMASS enabled, simply bit-shift multiply all Bresenham data by the max AMASS
// level, such that we never divide beyond the original data anywhere in the algorithm.
@@ -644,7 +903,7 @@ void st_prep_buffer()
prep.steps_remaining = (float)pl_block->step_event_count;
prep.step_per_mm = prep.steps_remaining/pl_block->millimeters;
prep.req_mm_increment = REQ_MM_INCREMENT_SCALAR/prep.step_per_mm;
- prep.dt_remainder = 0.0; // Reset for new segment block
+ prep.dt_remainder = 0.0f; // Reset for new segment block
if ((sys.step_control & STEP_CONTROL_EXECUTE_HOLD) || (prep.recalculate_flag & PREP_FLAG_DECEL_OVERRIDE)) {
// New block loaded mid-hold. Override planner block entry speed to enforce deceleration.
@@ -652,19 +911,20 @@ void st_prep_buffer()
pl_block->entry_speed_sqr = prep.exit_speed*prep.exit_speed;
prep.recalculate_flag &= ~(PREP_FLAG_DECEL_OVERRIDE);
} else {
- prep.current_speed = sqrt(pl_block->entry_speed_sqr);
+ prep.current_speed = sqrtf(pl_block->entry_speed_sqr);
}
-
+#ifdef VARIABLE_SPINDLE
// Setup laser mode variables. PWM rate adjusted motions will always complete a motion with the
// spindle off.
st_prep_block->is_pwm_rate_adjusted = false;
if (settings.flags & BITFLAG_LASER_MODE) {
- if (pl_block->condition & PL_COND_FLAG_SPINDLE_CCW) {
+ if (pl_block->condition & PL_COND_FLAG_SPINDLE_CCW) {
// Pre-compute inverse programmed rate to speed up PWM updating per step segment.
- prep.inv_rate = 1.0/pl_block->programmed_rate;
- st_prep_block->is_pwm_rate_adjusted = true;
+ prep.inv_rate = 1.0f / pl_block->programmed_rate;
+ st_prep_block->is_pwm_rate_adjusted = true;
}
}
+#endif
}
/* ---------------------------------------------------------------------------------
@@ -673,20 +933,20 @@ void st_prep_buffer()
planner has updated it. For a commanded forced-deceleration, such as from a feed
hold, override the planner velocities and decelerate to the target exit speed.
*/
- prep.mm_complete = 0.0; // Default velocity profile complete at 0.0mm from end of block.
- float inv_2_accel = 0.5/pl_block->acceleration;
+ prep.mm_complete = 0.0f; // Default velocity profile complete at 0.0mm from end of block.
+ float inv_2_accel = 0.5f/pl_block->acceleration;
if (sys.step_control & STEP_CONTROL_EXECUTE_HOLD) { // [Forced Deceleration to Zero Velocity]
// Compute velocity profile parameters for a feed hold in-progress. This profile overrides
// the planner block profile, enforcing a deceleration to zero speed.
prep.ramp_type = RAMP_DECEL;
// Compute decelerate distance relative to end of block.
float decel_dist = pl_block->millimeters - inv_2_accel*pl_block->entry_speed_sqr;
- if (decel_dist < 0.0) {
+ if (decel_dist < 0.0f) {
// Deceleration through entire planner block. End of feed hold is not in this block.
- prep.exit_speed = sqrt(pl_block->entry_speed_sqr-2*pl_block->acceleration*pl_block->millimeters);
+ prep.exit_speed = sqrtf(pl_block->entry_speed_sqr-2*pl_block->acceleration*pl_block->millimeters);
} else {
prep.mm_complete = decel_dist; // End of feed hold.
- prep.exit_speed = 0.0;
+ prep.exit_speed = 0.0f;
}
} else { // [Normal Operation]
// Compute or recompute velocity profile parameters of the prepped planner block.
@@ -696,26 +956,26 @@ void st_prep_buffer()
float exit_speed_sqr;
float nominal_speed;
if (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION) {
- prep.exit_speed = exit_speed_sqr = 0.0; // Enforce stop at end of system motion.
+ prep.exit_speed = exit_speed_sqr = 0.0f; // Enforce stop at end of system motion.
} else {
exit_speed_sqr = plan_get_exec_block_exit_speed_sqr();
- prep.exit_speed = sqrt(exit_speed_sqr);
+ prep.exit_speed = sqrtf(exit_speed_sqr);
}
nominal_speed = plan_compute_profile_nominal_speed(pl_block);
float nominal_speed_sqr = nominal_speed*nominal_speed;
float intersect_distance =
- 0.5*(pl_block->millimeters+inv_2_accel*(pl_block->entry_speed_sqr-exit_speed_sqr));
+ 0.5f*(pl_block->millimeters+inv_2_accel*(pl_block->entry_speed_sqr-exit_speed_sqr));
if (pl_block->entry_speed_sqr > nominal_speed_sqr) { // Only occurs during override reductions.
prep.accelerate_until = pl_block->millimeters - inv_2_accel*(pl_block->entry_speed_sqr-nominal_speed_sqr);
- if (prep.accelerate_until <= 0.0) { // Deceleration-only.
+ if (prep.accelerate_until <= 0.0f) { // Deceleration-only.
prep.ramp_type = RAMP_DECEL;
// prep.decelerate_after = pl_block->millimeters;
// prep.maximum_speed = prep.current_speed;
// Compute override block exit speed since it doesn't match the planner exit speed.
- prep.exit_speed = sqrt(pl_block->entry_speed_sqr - 2*pl_block->acceleration*pl_block->millimeters);
+ prep.exit_speed = sqrtf(pl_block->entry_speed_sqr - 2*pl_block->acceleration*pl_block->millimeters);
prep.recalculate_flag |= PREP_FLAG_DECEL_OVERRIDE; // Flag to load next block as deceleration override.
// TODO: Determine correct handling of parameters in deceleration-only.
@@ -724,11 +984,11 @@ void st_prep_buffer()
} else {
// Decelerate to cruise or cruise-decelerate types. Guaranteed to intersect updated plan.
- prep.decelerate_after = inv_2_accel*(nominal_speed_sqr-exit_speed_sqr);
- prep.maximum_speed = nominal_speed;
+ prep.decelerate_after = inv_2_accel*(nominal_speed_sqr-exit_speed_sqr); // Should always be >= 0.0 due to planner reinit.
+ prep.maximum_speed = nominal_speed;
prep.ramp_type = RAMP_DECEL_OVERRIDE;
}
- } else if (intersect_distance > 0.0) {
+ } else if (intersect_distance > 0.0f) {
if (intersect_distance < pl_block->millimeters) { // Either trapezoid or triangle types
// NOTE: For acceleration-cruise and cruise-only types, following calculation will be 0.0.
prep.decelerate_after = inv_2_accel*(nominal_speed_sqr-exit_speed_sqr);
@@ -744,7 +1004,7 @@ void st_prep_buffer()
} else { // Triangle type
prep.accelerate_until = intersect_distance;
prep.decelerate_after = intersect_distance;
- prep.maximum_speed = sqrt(2.0*pl_block->acceleration*intersect_distance+exit_speed_sqr);
+ prep.maximum_speed = sqrtf(2.0f*pl_block->acceleration*intersect_distance+exit_speed_sqr);
}
} else { // Deceleration-only type
prep.ramp_type = RAMP_DECEL;
@@ -752,8 +1012,8 @@ void st_prep_buffer()
// prep.maximum_speed = prep.current_speed;
}
} else { // Acceleration-only type
- prep.accelerate_until = 0.0;
- // prep.decelerate_after = 0.0;
+ prep.accelerate_until = 0.0f;
+ // prep.decelerate_after = 0.0f;
prep.maximum_speed = prep.exit_speed;
}
}
@@ -784,38 +1044,37 @@ void st_prep_buffer()
such as from a feed hold.
*/
float dt_max = DT_SEGMENT; // Maximum segment time
- float dt = 0.0; // Initialize segment time
+ float dt = 0.0f; // Initialize segment time
float time_var = dt_max; // Time worker variable
float mm_var; // mm-Distance worker variable
float speed_var; // Speed worker variable
float mm_remaining = pl_block->millimeters; // New segment distance from end of block.
float minimum_mm = mm_remaining-prep.req_mm_increment; // Guarantee at least one step.
- if (minimum_mm < 0.0) { minimum_mm = 0.0; }
+ if (minimum_mm < 0.0f) { minimum_mm = 0.0f; }
do {
switch (prep.ramp_type) {
case RAMP_DECEL_OVERRIDE:
speed_var = pl_block->acceleration*time_var;
- mm_var = time_var*(prep.current_speed - 0.5*speed_var);
- mm_remaining -= mm_var;
- if ((mm_remaining < prep.accelerate_until) || (mm_var <= 0)) {
+ if (prep.current_speed-prep.maximum_speed <= speed_var) {
// Cruise or cruise-deceleration types only for deceleration override.
- mm_remaining = prep.accelerate_until; // NOTE: 0.0 at EOB
- time_var = 2.0*(pl_block->millimeters-mm_remaining)/(prep.current_speed+prep.maximum_speed);
+ mm_remaining = prep.accelerate_until;
+ time_var = 2.0f*(pl_block->millimeters-mm_remaining)/(prep.current_speed+prep.maximum_speed);
prep.ramp_type = RAMP_CRUISE;
prep.current_speed = prep.maximum_speed;
} else { // Mid-deceleration override ramp.
+ mm_remaining -= time_var*(prep.current_speed - 0.5f*speed_var);
prep.current_speed -= speed_var;
}
break;
case RAMP_ACCEL:
// NOTE: Acceleration ramp only computes during first do-while loop.
speed_var = pl_block->acceleration*time_var;
- mm_remaining -= time_var*(prep.current_speed + 0.5*speed_var);
+ mm_remaining -= time_var*(prep.current_speed + 0.5f*speed_var);
if (mm_remaining < prep.accelerate_until) { // End of acceleration ramp.
// Acceleration-cruise, acceleration-deceleration ramp junction, or end of block.
mm_remaining = prep.accelerate_until; // NOTE: 0.0 at EOB
- time_var = 2.0*(pl_block->millimeters-mm_remaining)/(prep.current_speed+prep.maximum_speed);
+ time_var = 2.0f*(pl_block->millimeters-mm_remaining)/(prep.current_speed+prep.maximum_speed);
if (mm_remaining == prep.decelerate_after) { prep.ramp_type = RAMP_DECEL; }
else { prep.ramp_type = RAMP_CRUISE; }
prep.current_speed = prep.maximum_speed;
@@ -842,7 +1101,7 @@ void st_prep_buffer()
speed_var = pl_block->acceleration*time_var; // Used as delta speed (mm/min)
if (prep.current_speed > speed_var) { // Check if at or below zero speed.
// Compute distance from end of segment to end of block.
- mm_var = mm_remaining - time_var*(prep.current_speed - 0.5*speed_var); // (mm)
+ mm_var = mm_remaining - time_var*(prep.current_speed - 0.5f*speed_var); // (mm)
if (mm_var > prep.mm_complete) { // Typical case. In deceleration ramp.
mm_remaining = mm_var;
prep.current_speed -= speed_var;
@@ -850,7 +1109,7 @@ void st_prep_buffer()
}
}
// Otherwise, at end of block or end of forced-deceleration.
- time_var = 2.0*(mm_remaining-prep.mm_complete)/(prep.current_speed+prep.exit_speed);
+ time_var = 2.0f*(mm_remaining-prep.mm_complete)/(prep.current_speed+prep.exit_speed);
mm_remaining = prep.mm_complete;
prep.current_speed = prep.exit_speed;
}
@@ -872,7 +1131,7 @@ void st_prep_buffer()
/* -----------------------------------------------------------------------------------
Compute spindle speed PWM output for step segment
*/
-
+
if (st_prep_block->is_pwm_rate_adjusted || (sys.step_control & STEP_CONTROL_UPDATE_SPINDLE_PWM)) {
if (pl_block->condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)) {
float rpm = pl_block->spindle_speed;
@@ -881,11 +1140,12 @@ void st_prep_buffer()
// If current_speed is zero, then may need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE)
// but this would be instantaneous only and during a motion. May not matter at all.
prep.current_spindle_pwm = spindle_compute_pwm_value(rpm);
- } else {
+ }
+ else {
sys.spindle_speed = 0.0;
prep.current_spindle_pwm = SPINDLE_PWM_OFF_VALUE;
}
- bit_false(sys.step_control,STEP_CONTROL_UPDATE_SPINDLE_PWM);
+ bit_false(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
}
prep_segment->spindle_pwm = prep.current_spindle_pwm; // Reload segment PWM value
@@ -902,9 +1162,9 @@ void st_prep_buffer()
supported by Grbl (i.e. exceeding 10 meters axis travel at 200 step/mm).
*/
float step_dist_remaining = prep.step_per_mm*mm_remaining; // Convert mm_remaining to steps
- float n_steps_remaining = ceil(step_dist_remaining); // Round-up current steps remaining
- float last_n_steps_remaining = ceil(prep.steps_remaining); // Round-up last steps remaining
- prep_segment->n_step = last_n_steps_remaining-n_steps_remaining; // Compute number of steps to execute.
+ float n_steps_remaining = ceilf(step_dist_remaining); // Round-up current steps remaining
+ float last_n_steps_remaining = ceilf(prep.steps_remaining); // Round-up last steps remaining
+ prep_segment->n_step = (uint16_t)(last_n_steps_remaining - n_steps_remaining); // Compute number of steps to execute.
// Bail if we are at the end of a feed hold and don't have a step to execute.
if (prep_segment->n_step == 0) {
@@ -931,7 +1191,7 @@ void st_prep_buffer()
float inv_rate = dt/(last_n_steps_remaining - step_dist_remaining); // Compute adjusted step rate inverse
// Compute CPU cycles per step for the prepped segment.
- uint32_t cycles = ceil( (TICKS_PER_MICROSECOND*1000000*60)*inv_rate ); // (cycles/step)
+ uint32_t cycles = (uint32_t)ceilf((TICKS_PER_MICROSECOND * 1000000) *inv_rate * 60); // (cycles/step)
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
// Compute step timing and multi-axis smoothing level.
@@ -976,7 +1236,7 @@ void st_prep_buffer()
// Check for exit conditions and flag to load next planner block.
if (mm_remaining == prep.mm_complete) {
// End of planner block or forced-termination. No more distance to be executed.
- if (mm_remaining > 0.0) { // At end of forced-termination.
+ if (mm_remaining > 0.0f) { // At end of forced-termination.
// Reset prep parameters for resuming and then bail. Allow the stepper ISR to complete
// the segment queue, where realtime protocol will set new state upon receiving the
// cycle stop flag from the ISR. Prep_segment is blocked until then.
@@ -1011,3 +1271,30 @@ float st_get_realtime_rate()
}
return 0.0f;
}
+#ifdef STM32F103C8
+void TIM_Configuration(TIM_TypeDef* TIMER, u16 Period, u16 Prescaler, u8 PP)
+{
+ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
+ NVIC_InitTypeDef NVIC_InitStructure;
+
+ TIM_TimeBaseStructure.TIM_Period = Period - 1;
+ TIM_TimeBaseStructure.TIM_Prescaler = Prescaler - 1;
+ TIM_TimeBaseStructure.TIM_ClockDivision = 0;
+ TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
+ TIM_TimeBaseInit(TIMER, &TIM_TimeBaseStructure);
+
+ TIM_ClearITPendingBit(TIMER, TIM_IT_Update);
+ TIM_ITConfig(TIMER, TIM_IT_Update, ENABLE);
+ TIM_Cmd(TIMER, ENABLE);
+
+ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
+ if (TIMER == TIM2) { NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; }
+ else if (TIMER == TIM3) { NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; }
+ else if (TIMER == TIM4) { NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; }
+
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PP;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+}
+#endif
diff --git a/grbl/stepper.h b/grbl/stepper.h
index 41871a66..f24e1f00 100644
--- a/grbl/stepper.h
+++ b/grbl/stepper.h
@@ -23,7 +23,11 @@
#define stepper_h
#ifndef SEGMENT_BUFFER_SIZE
- #define SEGMENT_BUFFER_SIZE 6
+#ifdef AVRTARGET
+#define SEGMENT_BUFFER_SIZE 6
+#else
+#define SEGMENT_BUFFER_SIZE 10
+#endif
#endif
// Initialize and setup the stepper motor subsystem
@@ -56,4 +60,8 @@ void st_update_plan_block_parameters();
// Called by realtime status reporting if realtime rate reporting is enabled in config.h.
float st_get_realtime_rate();
+extern const PORTPINDEF step_pin_mask[N_AXIS];
+extern const PORTPINDEF direction_pin_mask[N_AXIS];
+extern const PORTPINDEF limit_pin_mask[N_AXIS];
+
#endif
diff --git a/grbl/system.c b/grbl/system.c
index 14f56fd6..9b7be50f 100644
--- a/grbl/system.c
+++ b/grbl/system.c
@@ -23,6 +23,7 @@
void system_init()
{
+#ifdef AVRTARGET
CONTROL_DDR &= ~(CONTROL_MASK); // Configure as input pins
#ifdef DISABLE_CONTROL_PIN_PULL_UP
CONTROL_PORT &= ~(CONTROL_MASK); // Normal low operation. Requires external pull-down.
@@ -31,6 +32,38 @@ void system_init()
#endif
CONTROL_PCMSK |= CONTROL_MASK; // Enable specific pins of the Pin Change Interrupt
PCICR |= (1 << CONTROL_INT); // Enable Pin Change Interrupt
+#endif
+#ifdef STM32F103C8
+ GPIO_InitTypeDef GPIO_InitStructure;
+ RCC_APB2PeriphClockCmd(RCC_CONTROL_PORT | RCC_APB2Periph_AFIO, ENABLE);
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+#ifdef DISABLE_CONTROL_PIN_PULL_UP
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
+#else
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
+#endif
+ GPIO_InitStructure.GPIO_Pin = CONTROL_MASK;
+ GPIO_Init(CONTROL_PORT, &GPIO_InitStructure);
+
+ GPIO_EXTILineConfig(GPIO_CONTROL_PORT, CONTROL_RESET_BIT);
+ GPIO_EXTILineConfig(GPIO_CONTROL_PORT, CONTROL_FEED_HOLD_BIT);
+ GPIO_EXTILineConfig(GPIO_CONTROL_PORT, CONTROL_CYCLE_START_BIT);
+ GPIO_EXTILineConfig(GPIO_CONTROL_PORT, CONTROL_SAFETY_DOOR_BIT);
+
+ EXTI_InitTypeDef EXTI_InitStructure;
+ EXTI_InitStructure.EXTI_Line = CONTROL_MASK; //
+ EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //Interrupt mode, optional values for the interrupt EXTI_Mode_Interrupt and event EXTI_Mode_Event.
+ EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //Trigger mode, can be a falling edge trigger EXTI_Trigger_Falling, the rising edge triggered EXTI_Trigger_Rising, or any level (rising edge and falling edge trigger EXTI_Trigger_Rising_Falling)
+ EXTI_InitStructure.EXTI_LineCmd = ENABLE;
+ EXTI_Init(&EXTI_InitStructure);
+
+ NVIC_InitTypeDef NVIC_InitStructure;
+ NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //Enable keypad external interrupt channel
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //Priority 2,
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //Sub priority 2
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //Enable external interrupt channel
+ NVIC_Init(&NVIC_InitStructure);
+#endif
}
@@ -40,7 +73,15 @@ void system_init()
uint8_t system_control_get_state()
{
uint8_t control_state = 0;
+#ifdef AVRTARGET
uint8_t pin = (CONTROL_PIN & CONTROL_MASK);
+#endif
+#ifdef WIN32
+ uint8_t pin = 0;
+#endif
+#ifdef STM32F103C8
+ uint16_t pin= GPIO_ReadInputData(CONTROL_PIN_PORT);
+#endif
#ifdef INVERT_CONTROL_PIN_MASK
pin ^= INVERT_CONTROL_PIN_MASK;
#endif
@@ -60,6 +101,7 @@ uint8_t system_control_get_state()
// only the realtime command execute variable to have the main program execute these when
// its ready. This works exactly like the character-based realtime commands when picked off
// directly from the incoming serial data stream.
+#ifdef AVRTARGET
ISR(CONTROL_INT_vect)
{
uint8_t pin = system_control_get_state();
@@ -78,7 +120,37 @@ ISR(CONTROL_INT_vect)
}
}
}
-
+#endif
+#if defined (STM32F103C8)
+void EXTI9_5_IRQHandler(void)
+{
+ EXTI_ClearITPendingBit((1 << CONTROL_RESET_BIT) | (1 << CONTROL_FEED_HOLD_BIT) | (1 << CONTROL_CYCLE_START_BIT) | (1 << CONTROL_SAFETY_DOOR_BIT));
+ uint8_t pin = system_control_get_state();
+ if (pin)
+ {
+ if (bit_istrue(pin,CONTROL_PIN_INDEX_RESET))
+ {
+ mc_reset();
+ }
+ else if (bit_istrue(pin, CONTROL_PIN_INDEX_CYCLE_START))
+ {
+ bit_true(sys_rt_exec_state, EXEC_CYCLE_START);
+ }
+#ifndef ENABLE_SAFETY_DOOR_INPUT_PIN
+ else if (bit_istrue(pin, CONTROL_PIN_INDEX_FEED_HOLD))
+ {
+ bit_true(sys_rt_exec_state, EXEC_FEED_HOLD);
+ }
+#else
+ else if (bit_istrue(pin, CONTROL_PIN_INDEX_SAFETY_DOOR))
+ {
+ bit_true(sys_rt_exec_state, EXEC_SAFETY_DOOR);
+ }
+#endif
+ NVIC_ClearPendingIRQ(EXTI9_5_IRQn);
+}
+}
+#endif
// Returns if safety door is ajar(T) or closed(F), based on pin state.
uint8_t system_check_safety_door_ajar()
@@ -259,7 +331,7 @@ uint8_t system_execute_line(char *line)
helper_var = gc_execute_line(line); // Set helper_var to returned status code.
if (helper_var) { return(helper_var); }
else {
- helper_var = trunc(parameter); // Set helper_var to int value of parameter
+ helper_var = truncf(parameter); // Set helper_var to int value of parameter
settings_store_startup_line(helper_var,line);
}
} else { // Store global setting.
@@ -348,60 +420,159 @@ uint8_t system_check_travel_limits(float *target)
return(false);
}
+#ifdef WIN32
+extern CRITICAL_SECTION CriticalSection;
+#endif
// Special handlers for setting and clearing Grbl's real-time execution flags.
void system_set_exec_state_flag(uint8_t mask) {
+#ifdef AVRTARGET
uint8_t sreg = SREG;
cli();
sys_rt_exec_state |= (mask);
SREG = sreg;
+#endif
+#ifdef WIN32
+ EnterCriticalSection(&CriticalSection);
+ sys_rt_exec_state |= (mask);
+ LeaveCriticalSection(&CriticalSection);
+#endif
+#ifdef STM32F103C8
+ __disable_irq();
+ sys_rt_exec_state |= (mask);
+ __enable_irq();
+#endif
}
void system_clear_exec_state_flag(uint8_t mask) {
+#ifdef AVRTARGET
uint8_t sreg = SREG;
cli();
sys_rt_exec_state &= ~(mask);
SREG = sreg;
+#endif
+#ifdef WIN32
+ EnterCriticalSection(&CriticalSection);
+ sys_rt_exec_state &= ~(mask);
+ LeaveCriticalSection(&CriticalSection);
+#endif
+#ifdef STM32F103C8
+ __disable_irq();
+ sys_rt_exec_state &= ~(mask);
+ __enable_irq();
+#endif
}
void system_set_exec_alarm(uint8_t code) {
+#ifdef AVRTARGET
uint8_t sreg = SREG;
cli();
sys_rt_exec_alarm = code;
SREG = sreg;
+#endif
+#ifdef WIN32
+ EnterCriticalSection(&CriticalSection);
+ sys_rt_exec_alarm |= (code);
+ LeaveCriticalSection(&CriticalSection);
+#endif
+#ifdef STM32F103C8
+ __disable_irq();
+ sys_rt_exec_alarm |= (code);
+ __enable_irq();
+#endif
}
-void system_clear_exec_alarm_flag(uint8_t mask) {
+void system_clear_exec_alarm() {
+#ifdef AVRTARGET
uint8_t sreg = SREG;
cli();
- sys_rt_exec_alarm &= ~(mask);
+ sys_rt_exec_alarm = 0;
SREG = sreg;
+#endif
+#ifdef WIN32
+ EnterCriticalSection(&CriticalSection);
+ sys_rt_exec_alarm = 0;
+ LeaveCriticalSection(&CriticalSection);
+#endif
+#ifdef STM32F103C8
+ __disable_irq();
+ sys_rt_exec_alarm = 0;
+ __enable_irq();
+#endif
}
void system_set_exec_motion_override_flag(uint8_t mask) {
+#ifdef AVRTARGET
uint8_t sreg = SREG;
cli();
sys_rt_exec_motion_override |= (mask);
SREG = sreg;
+#endif
+#ifdef WIN32
+ EnterCriticalSection(&CriticalSection);
+ sys_rt_exec_motion_override |= (mask);
+ LeaveCriticalSection(&CriticalSection);
+#endif
+#ifdef STM32F103C8
+ __disable_irq();
+ sys_rt_exec_motion_override |= (mask);
+ __enable_irq();
+#endif
}
void system_set_exec_accessory_override_flag(uint8_t mask) {
- uint8_t sreg = SREG;
+#ifdef AVRTARGET
+ uint8_t sreg = SREG;
cli();
sys_rt_exec_accessory_override |= (mask);
SREG = sreg;
+#endif
+#ifdef WIN32
+ EnterCriticalSection(&CriticalSection);
+ sys_rt_exec_accessory_override |= (mask);
+ LeaveCriticalSection(&CriticalSection);
+#endif
+#ifdef STM32F103C8
+ __disable_irq();
+ sys_rt_exec_accessory_override |= (mask);
+ __enable_irq();
+#endif
}
void system_clear_exec_motion_overrides() {
- uint8_t sreg = SREG;
+#ifdef AVRTARGET
+ uint8_t sreg = SREG;
cli();
sys_rt_exec_motion_override = 0;
SREG = sreg;
+#endif
+#ifdef WIN32
+ EnterCriticalSection(&CriticalSection);
+ sys_rt_exec_motion_override = 0;
+ LeaveCriticalSection(&CriticalSection);
+#endif
+#ifdef STM32F103C8
+ __disable_irq();
+ sys_rt_exec_motion_override = 0;
+ __enable_irq();
+#endif
}
void system_clear_exec_accessory_overrides() {
+#ifdef AVRTARGET
uint8_t sreg = SREG;
cli();
sys_rt_exec_accessory_override = 0;
SREG = sreg;
+#endif
+#ifdef WIN32
+ EnterCriticalSection(&CriticalSection);
+ sys_rt_exec_accessory_override = 0;
+ LeaveCriticalSection(&CriticalSection);
+#endif
+#ifdef STM32F103C8
+ __disable_irq();
+ sys_rt_exec_accessory_override = 0;
+ __enable_irq();
+#endif
}
diff --git a/grbl/system.h b/grbl/system.h
index a4ca8185..6249b8c1 100644
--- a/grbl/system.h
+++ b/grbl/system.h
@@ -137,25 +137,28 @@ typedef struct {
uint8_t spindle_stop_ovr; // Tracks spindle stop override states
uint8_t report_ovr_counter; // Tracks when to add override data to status reports.
uint8_t report_wco_counter; // Tracks when to add work coordinate offset data to status reports.
- #ifdef VARIABLE_SPINDLE
+ #ifdef ENABLE_PARKING_OVERRIDE_CONTROL
+ uint8_t override_ctrl; // Tracks override control states.
+ #endif
+ #ifdef VARIABLE_SPINDLE
float spindle_speed;
#endif
} system_t;
extern system_t sys;
// NOTE: These position variables may need to be declared as volatiles, if problems arise.
-int32_t sys_position[N_AXIS]; // Real-time machine (aka home) position vector in steps.
-int32_t sys_probe_position[N_AXIS]; // Last probe position in machine coordinates and steps.
+extern int32_t sys_position[N_AXIS]; // Real-time machine (aka home) position vector in steps.
+extern int32_t sys_probe_position[N_AXIS]; // Last probe position in machine coordinates and steps.
-volatile uint8_t sys_probe_state; // Probing state value. Used to coordinate the probing cycle with stepper ISR.
-volatile uint8_t sys_rt_exec_state; // Global realtime executor bitflag variable for state management. See EXEC bitmasks.
-volatile uint8_t sys_rt_exec_alarm; // Global realtime executor bitflag variable for setting various alarms.
-volatile uint8_t sys_rt_exec_motion_override; // Global realtime executor bitflag variable for motion-based overrides.
-volatile uint8_t sys_rt_exec_accessory_override; // Global realtime executor bitflag variable for spindle/coolant overrides.
+extern volatile uint8_t sys_probe_state; // Probing state value. Used to coordinate the probing cycle with stepper ISR.
+extern volatile uint8_t sys_rt_exec_state; // Global realtime executor bitflag variable for state management. See EXEC bitmasks.
+extern volatile uint8_t sys_rt_exec_alarm; // Global realtime executor bitflag variable for setting various alarms.
+extern volatile uint8_t sys_rt_exec_motion_override; // Global realtime executor bitflag variable for motion-based overrides.
+extern volatile uint8_t sys_rt_exec_accessory_override; // Global realtime executor bitflag variable for spindle/coolant overrides.
#ifdef DEBUG
#define EXEC_DEBUG_REPORT bit(0)
- volatile uint8_t sys_rt_exec_debug;
+ extern volatile uint8_t sys_rt_exec_debug;
#endif
// Initialize the serial protocol
@@ -195,7 +198,7 @@ uint8_t system_check_travel_limits(float *target);
void system_set_exec_state_flag(uint8_t mask);
void system_clear_exec_state_flag(uint8_t mask);
void system_set_exec_alarm(uint8_t code);
-void system_clear_exec_alarm_flag(uint8_t mask);
+void system_clear_exec_alarm();
void system_set_exec_motion_override_flag(uint8_t mask);
void system_set_exec_accessory_override_flag(uint8_t mask);
void system_clear_exec_motion_overrides();
diff --git a/grblwin/.vs/grblwin/v14/.suo b/grblwin/.vs/grblwin/v14/.suo
new file mode 100644
index 00000000..b3a231d7
Binary files /dev/null and b/grblwin/.vs/grblwin/v14/.suo differ
diff --git a/grblwin/ReadMe.txt b/grblwin/ReadMe.txt
new file mode 100644
index 00000000..cd0975e3
--- /dev/null
+++ b/grblwin/ReadMe.txt
@@ -0,0 +1,40 @@
+========================================================================
+ CONSOLE APPLICATION : grblwin Project Overview
+========================================================================
+
+AppWizard has created this grblwin application for you.
+
+This file contains a summary of what you will find in each of the files that
+make up your grblwin application.
+
+
+grblwin.vcxproj
+ This is the main project file for VC++ projects generated using an Application Wizard.
+ It contains information about the version of Visual C++ that generated the file, and
+ information about the platforms, configurations, and project features selected with the
+ Application Wizard.
+
+grblwin.vcxproj.filters
+ This is the filters file for VC++ projects generated using an Application Wizard.
+ It contains information about the association between the files in your project
+ and the filters. This association is used in the IDE to show grouping of files with
+ similar extensions under a specific node (for e.g. ".cpp" files are associated with the
+ "Source Files" filter).
+
+grblwin.cpp
+ This is the main application source file.
+
+/////////////////////////////////////////////////////////////////////////////
+Other standard files:
+
+StdAfx.h, StdAfx.cpp
+ These files are used to build a precompiled header (PCH) file
+ named grblwin.pch and a precompiled types file named StdAfx.obj.
+
+/////////////////////////////////////////////////////////////////////////////
+Other notes:
+
+AppWizard uses "TODO:" comments to indicate parts of the source code you
+should add to or customize.
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/grblwin/eeprom.bin b/grblwin/eeprom.bin
new file mode 100644
index 00000000..a2c849ea
Binary files /dev/null and b/grblwin/eeprom.bin differ
diff --git a/grblwin/grblwin.VC.db b/grblwin/grblwin.VC.db
new file mode 100644
index 00000000..f2556e7e
Binary files /dev/null and b/grblwin/grblwin.VC.db differ
diff --git a/grblwin/grblwin.sdf b/grblwin/grblwin.sdf
new file mode 100644
index 00000000..0900407b
Binary files /dev/null and b/grblwin/grblwin.sdf differ
diff --git a/grblwin/grblwin.sln b/grblwin/grblwin.sln
new file mode 100644
index 00000000..f92e6f09
--- /dev/null
+++ b/grblwin/grblwin.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grblwin", "grblwin.vcxproj", "{8785D33C-F44C-44FA-9A16-0C93B895F459}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {8785D33C-F44C-44FA-9A16-0C93B895F459}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8785D33C-F44C-44FA-9A16-0C93B895F459}.Debug|Win32.Build.0 = Debug|Win32
+ {8785D33C-F44C-44FA-9A16-0C93B895F459}.Release|Win32.ActiveCfg = Release|Win32
+ {8785D33C-F44C-44FA-9A16-0C93B895F459}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/grblwin/grblwin.suo b/grblwin/grblwin.suo
new file mode 100644
index 00000000..d5b87ca6
Binary files /dev/null and b/grblwin/grblwin.suo differ
diff --git a/grblwin/grblwin.v12.suo b/grblwin/grblwin.v12.suo
new file mode 100644
index 00000000..9475efb6
Binary files /dev/null and b/grblwin/grblwin.v12.suo differ
diff --git a/grblwin/grblwin.vcxproj b/grblwin/grblwin.vcxproj
new file mode 100644
index 00000000..75070976
--- /dev/null
+++ b/grblwin/grblwin.vcxproj
@@ -0,0 +1,129 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+
+ {8785D33C-F44C-44FA-9A16-0C93B895F459}
+ Win32Proj
+ grblwin
+
+
+
+ Application
+ true
+ Unicode
+ v140
+
+
+ Application
+ false
+ true
+ Unicode
+ v140
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ j:\buildoutput\grblwin11\Debug\
+ $(OutDir)\
+
+
+ false
+ j:\buildoutput\grblwin11\Release\
+ $(OutDir)\
+
+
+
+ NotUsing
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ NotUsing
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/grblwin/grblwin.vcxproj.filters b/grblwin/grblwin.vcxproj.filters
new file mode 100644
index 00000000..5a84ad98
--- /dev/null
+++ b/grblwin/grblwin.vcxproj.filters
@@ -0,0 +1,141 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/grblwin/grblwin.vcxproj.user b/grblwin/grblwin.vcxproj.user
new file mode 100644
index 00000000..9a82ae79
--- /dev/null
+++ b/grblwin/grblwin.vcxproj.user
@@ -0,0 +1,7 @@
+
+
+
+ COM4
+ WindowsLocalDebugger
+
+
\ No newline at end of file
diff --git a/grblwin/ipch/grblwin-905085aa/grblwin-3bc7f0ad.ipch b/grblwin/ipch/grblwin-905085aa/grblwin-3bc7f0ad.ipch
new file mode 100644
index 00000000..69cc64a3
Binary files /dev/null and b/grblwin/ipch/grblwin-905085aa/grblwin-3bc7f0ad.ipch differ
diff --git a/stm32grbl.cogui b/stm32grbl.cogui
new file mode 100644
index 00000000..b8bd5b01
--- /dev/null
+++ b/stm32grbl.cogui
@@ -0,0 +1,340 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/stm32grbl.comarker b/stm32grbl.comarker
new file mode 100644
index 00000000..69f7928d
--- /dev/null
+++ b/stm32grbl.comarker
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/stm32grbl11.coproj b/stm32grbl11.coproj
new file mode 100644
index 00000000..c41d616d
--- /dev/null
+++ b/stm32grbl11.coproj
@@ -0,0 +1,186 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/stm32grbl11d.coproj b/stm32grbl11d.coproj
new file mode 100644
index 00000000..cedb7383
--- /dev/null
+++ b/stm32grbl11d.coproj
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/stm_lib/inc/misc.h b/stm_lib/inc/misc.h
new file mode 100644
index 00000000..9a6bd07c
--- /dev/null
+++ b/stm_lib/inc/misc.h
@@ -0,0 +1,220 @@
+/**
+ ******************************************************************************
+ * @file misc.h
+ * @author MCD Application Team
+ * @version V3.5.0
+ * @date 11-March-2011
+ * @brief This file contains all the functions prototypes for the miscellaneous
+ * firmware library functions (add-on to CMSIS functions).
+ ******************************************************************************
+ * @attention
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32f10x_flash.h"
+
+/** @addtogroup STM32F10x_StdPeriph_Driver
+ * @{
+ */
+
+/** @defgroup FLASH
+ * @brief FLASH driver modules
+ * @{
+ */
+
+/** @defgroup FLASH_Private_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup FLASH_Private_Defines
+ * @{
+ */
+
+/* Flash Access Control Register bits */
+#define ACR_LATENCY_Mask ((uint32_t)0x00000038)
+#define ACR_HLFCYA_Mask ((uint32_t)0xFFFFFFF7)
+#define ACR_PRFTBE_Mask ((uint32_t)0xFFFFFFEF)
+
+/* Flash Access Control Register bits */
+#define ACR_PRFTBS_Mask ((uint32_t)0x00000020)
+
+/* Flash Control Register bits */
+#define CR_PG_Set ((uint32_t)0x00000001)
+#define CR_PG_Reset ((uint32_t)0x00001FFE)
+#define CR_PER_Set ((uint32_t)0x00000002)
+#define CR_PER_Reset ((uint32_t)0x00001FFD)
+#define CR_MER_Set ((uint32_t)0x00000004)
+#define CR_MER_Reset ((uint32_t)0x00001FFB)
+#define CR_OPTPG_Set ((uint32_t)0x00000010)
+#define CR_OPTPG_Reset ((uint32_t)0x00001FEF)
+#define CR_OPTER_Set ((uint32_t)0x00000020)
+#define CR_OPTER_Reset ((uint32_t)0x00001FDF)
+#define CR_STRT_Set ((uint32_t)0x00000040)
+#define CR_LOCK_Set ((uint32_t)0x00000080)
+
+/* FLASH Mask */
+#define RDPRT_Mask ((uint32_t)0x00000002)
+#define WRP0_Mask ((uint32_t)0x000000FF)
+#define WRP1_Mask ((uint32_t)0x0000FF00)
+#define WRP2_Mask ((uint32_t)0x00FF0000)
+#define WRP3_Mask ((uint32_t)0xFF000000)
+#define OB_USER_BFB2 ((uint16_t)0x0008)
+
+/* FLASH Keys */
+#define RDP_Key ((uint16_t)0x00A5)
+#define FLASH_KEY1 ((uint32_t)0x45670123)
+#define FLASH_KEY2 ((uint32_t)0xCDEF89AB)
+
+/* FLASH BANK address */
+#define FLASH_BANK1_END_ADDRESS ((uint32_t)0x807FFFF)
+
+/* Delay definition */
+#define EraseTimeout ((uint32_t)0x000B0000)
+#define ProgramTimeout ((uint32_t)0x00002000)
+/**
+ * @}
+ */
+
+/** @defgroup FLASH_Private_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup FLASH_Private_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup FLASH_Private_FunctionPrototypes
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup FLASH_Private_Functions
+ * @{
+ */
+
+/**
+@code
+
+ This driver provides functions to configure and program the Flash memory of all STM32F10x devices,
+ including the latest STM32F10x_XL density devices.
+
+ STM32F10x_XL devices feature up to 1 Mbyte with dual bank architecture for read-while-write (RWW) capability:
+ - bank1: fixed size of 512 Kbytes (256 pages of 2Kbytes each)
+ - bank2: up to 512 Kbytes (up to 256 pages of 2Kbytes each)
+ While other STM32F10x devices features only one bank with memory up to 512 Kbytes.
+
+ In version V3.3.0, some functions were updated and new ones were added to support
+ STM32F10x_XL devices. Thus some functions manages all devices, while other are
+ dedicated for XL devices only.
+
+ The table below presents the list of available functions depending on the used STM32F10x devices.
+
+ ***************************************************
+ * Legacy functions used for all STM32F10x devices *
+ ***************************************************
+ +----------------------------------------------------------------------------------------------------------------------------------+
+ | Functions prototypes |STM32F10x_XL|Other STM32F10x| Comments |
+ | | devices | devices | |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_SetLatency | Yes | Yes | No change |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_HalfCycleAccessCmd | Yes | Yes | No change |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_PrefetchBufferCmd | Yes | Yes | No change |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_Unlock | Yes | Yes | - For STM32F10X_XL devices: unlock Bank1 and Bank2. |
+ | | | | - For other devices: unlock Bank1 and it is equivalent |
+ | | | | to FLASH_UnlockBank1 function. |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_Lock | Yes | Yes | - For STM32F10X_XL devices: lock Bank1 and Bank2. |
+ | | | | - For other devices: lock Bank1 and it is equivalent |
+ | | | | to FLASH_LockBank1 function. |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_ErasePage | Yes | Yes | - For STM32F10x_XL devices: erase a page in Bank1 and Bank2 |
+ | | | | - For other devices: erase a page in Bank1 |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_EraseAllPages | Yes | Yes | - For STM32F10x_XL devices: erase all pages in Bank1 and Bank2 |
+ | | | | - For other devices: erase all pages in Bank1 |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_EraseOptionBytes | Yes | Yes | No change |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_ProgramWord | Yes | Yes | Updated to program up to 1MByte (depending on the used device) |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_ProgramHalfWord | Yes | Yes | Updated to program up to 1MByte (depending on the used device) |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_ProgramOptionByteData | Yes | Yes | No change |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_EnableWriteProtection | Yes | Yes | No change |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_ReadOutProtection | Yes | Yes | No change |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_UserOptionByteConfig | Yes | Yes | No change |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_GetUserOptionByte | Yes | Yes | No change |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_GetWriteProtectionOptionByte | Yes | Yes | No change |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_GetReadOutProtectionStatus | Yes | Yes | No change |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_GetPrefetchBufferStatus | Yes | Yes | No change |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_ITConfig | Yes | Yes | - For STM32F10x_XL devices: enable Bank1 and Bank2's interrupts|
+ | | | | - For other devices: enable Bank1's interrupts |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_GetFlagStatus | Yes | Yes | - For STM32F10x_XL devices: return Bank1 and Bank2's flag status|
+ | | | | - For other devices: return Bank1's flag status |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_ClearFlag | Yes | Yes | - For STM32F10x_XL devices: clear Bank1 and Bank2's flag |
+ | | | | - For other devices: clear Bank1's flag |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_GetStatus | Yes | Yes | - Return the status of Bank1 (for all devices) |
+ | | | | equivalent to FLASH_GetBank1Status function |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_WaitForLastOperation | Yes | Yes | - Wait for Bank1 last operation (for all devices) |
+ | | | | equivalent to: FLASH_WaitForLastBank1Operation function |
+ +----------------------------------------------------------------------------------------------------------------------------------+
+
+ ************************************************************************************************************************
+ * New functions used for all STM32F10x devices to manage Bank1: *
+ * - These functions are mainly useful for STM32F10x_XL density devices, to have separate control for Bank1 and bank2 *
+ * - For other devices, these functions are optional (covered by functions listed above) *
+ ************************************************************************************************************************
+ +----------------------------------------------------------------------------------------------------------------------------------+
+ | Functions prototypes |STM32F10x_XL|Other STM32F10x| Comments |
+ | | devices | devices | |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ | FLASH_UnlockBank1 | Yes | Yes | - Unlock Bank1 |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_LockBank1 | Yes | Yes | - Lock Bank1 |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ | FLASH_EraseAllBank1Pages | Yes | Yes | - Erase all pages in Bank1 |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ | FLASH_GetBank1Status | Yes | Yes | - Return the status of Bank1 |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ | FLASH_WaitForLastBank1Operation | Yes | Yes | - Wait for Bank1 last operation |
+ +----------------------------------------------------------------------------------------------------------------------------------+
+
+ *****************************************************************************
+ * New Functions used only with STM32F10x_XL density devices to manage Bank2 *
+ *****************************************************************************
+ +----------------------------------------------------------------------------------------------------------------------------------+
+ | Functions prototypes |STM32F10x_XL|Other STM32F10x| Comments |
+ | | devices | devices | |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ | FLASH_UnlockBank2 | Yes | No | - Unlock Bank2 |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ |FLASH_LockBank2 | Yes | No | - Lock Bank2 |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ | FLASH_EraseAllBank2Pages | Yes | No | - Erase all pages in Bank2 |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ | FLASH_GetBank2Status | Yes | No | - Return the status of Bank2 |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ | FLASH_WaitForLastBank2Operation | Yes | No | - Wait for Bank2 last operation |
+ |----------------------------------------------------------------------------------------------------------------------------------|
+ | FLASH_BootConfig | Yes | No | - Configure to boot from Bank1 or Bank2 |
+ +----------------------------------------------------------------------------------------------------------------------------------+
+@endcode
+*/
+
+
+/**
+ * @brief Sets the code latency value.
+ * @note This function can be used for all STM32F10x devices.
+ * @param FLASH_Latency: specifies the FLASH Latency value.
+ * This parameter can be one of the following values:
+ * @arg FLASH_Latency_0: FLASH Zero Latency cycle
+ * @arg FLASH_Latency_1: FLASH One Latency cycle
+ * @arg FLASH_Latency_2: FLASH Two Latency cycles
+ * @retval None
+ */
+void FLASH_SetLatency(uint32_t FLASH_Latency)
+{
+ uint32_t tmpreg = 0;
+
+ /* Check the parameters */
+ assert_param(IS_FLASH_LATENCY(FLASH_Latency));
+
+ /* Read the ACR register */
+ tmpreg = FLASH->ACR;
+
+ /* Sets the Latency value */
+ tmpreg &= ACR_LATENCY_Mask;
+ tmpreg |= FLASH_Latency;
+
+ /* Write the ACR register */
+ FLASH->ACR = tmpreg;
+}
+
+/**
+ * @brief Enables or disables the Half cycle flash access.
+ * @note This function can be used for all STM32F10x devices.
+ * @param FLASH_HalfCycleAccess: specifies the FLASH Half cycle Access mode.
+ * This parameter can be one of the following values:
+ * @arg FLASH_HalfCycleAccess_Enable: FLASH Half Cycle Enable
+ * @arg FLASH_HalfCycleAccess_Disable: FLASH Half Cycle Disable
+ * @retval None
+ */
+void FLASH_HalfCycleAccessCmd(uint32_t FLASH_HalfCycleAccess)
+{
+ /* Check the parameters */
+ assert_param(IS_FLASH_HALFCYCLEACCESS_STATE(FLASH_HalfCycleAccess));
+
+ /* Enable or disable the Half cycle access */
+ FLASH->ACR &= ACR_HLFCYA_Mask;
+ FLASH->ACR |= FLASH_HalfCycleAccess;
+}
+
+/**
+ * @brief Enables or disables the Prefetch Buffer.
+ * @note This function can be used for all STM32F10x devices.
+ * @param FLASH_PrefetchBuffer: specifies the Prefetch buffer status.
+ * This parameter can be one of the following values:
+ * @arg FLASH_PrefetchBuffer_Enable: FLASH Prefetch Buffer Enable
+ * @arg FLASH_PrefetchBuffer_Disable: FLASH Prefetch Buffer Disable
+ * @retval None
+ */
+void FLASH_PrefetchBufferCmd(uint32_t FLASH_PrefetchBuffer)
+{
+ /* Check the parameters */
+ assert_param(IS_FLASH_PREFETCHBUFFER_STATE(FLASH_PrefetchBuffer));
+
+ /* Enable or disable the Prefetch Buffer */
+ FLASH->ACR &= ACR_PRFTBE_Mask;
+ FLASH->ACR |= FLASH_PrefetchBuffer;
+}
+
+/**
+ * @brief Unlocks the FLASH Program Erase Controller.
+ * @note This function can be used for all STM32F10x devices.
+ * - For STM32F10X_XL devices this function unlocks Bank1 and Bank2.
+ * - For all other devices it unlocks Bank1 and it is equivalent
+ * to FLASH_UnlockBank1 function..
+ * @param None
+ * @retval None
+ */
+void FLASH_Unlock(void)
+{
+ /* Authorize the FPEC of Bank1 Access */
+ FLASH->KEYR = FLASH_KEY1;
+ FLASH->KEYR = FLASH_KEY2;
+
+#ifdef STM32F10X_XL
+ /* Authorize the FPEC of Bank2 Access */
+ FLASH->KEYR2 = FLASH_KEY1;
+ FLASH->KEYR2 = FLASH_KEY2;
+#endif /* STM32F10X_XL */
+}
+/**
+ * @brief Unlocks the FLASH Bank1 Program Erase Controller.
+ * @note This function can be used for all STM32F10x devices.
+ * - For STM32F10X_XL devices this function unlocks Bank1.
+ * - For all other devices it unlocks Bank1 and it is
+ * equivalent to FLASH_Unlock function.
+ * @param None
+ * @retval None
+ */
+void FLASH_UnlockBank1(void)
+{
+ /* Authorize the FPEC of Bank1 Access */
+ FLASH->KEYR = FLASH_KEY1;
+ FLASH->KEYR = FLASH_KEY2;
+}
+
+#ifdef STM32F10X_XL
+/**
+ * @brief Unlocks the FLASH Bank2 Program Erase Controller.
+ * @note This function can be used only for STM32F10X_XL density devices.
+ * @param None
+ * @retval None
+ */
+void FLASH_UnlockBank2(void)
+{
+ /* Authorize the FPEC of Bank2 Access */
+ FLASH->KEYR2 = FLASH_KEY1;
+ FLASH->KEYR2 = FLASH_KEY2;
+
+}
+#endif /* STM32F10X_XL */
+
+/**
+ * @brief Locks the FLASH Program Erase Controller.
+ * @note This function can be used for all STM32F10x devices.
+ * - For STM32F10X_XL devices this function Locks Bank1 and Bank2.
+ * - For all other devices it Locks Bank1 and it is equivalent
+ * to FLASH_LockBank1 function.
+ * @param None
+ * @retval None
+ */
+void FLASH_Lock(void)
+{
+ /* Set the Lock Bit to lock the FPEC and the CR of Bank1 */
+ FLASH->CR |= CR_LOCK_Set;
+
+#ifdef STM32F10X_XL
+ /* Set the Lock Bit to lock the FPEC and the CR of Bank2 */
+ FLASH->CR2 |= CR_LOCK_Set;
+#endif /* STM32F10X_XL */
+}
+
+/**
+ * @brief Locks the FLASH Bank1 Program Erase Controller.
+ * @note this function can be used for all STM32F10x devices.
+ * - For STM32F10X_XL devices this function Locks Bank1.
+ * - For all other devices it Locks Bank1 and it is equivalent
+ * to FLASH_Lock function.
+ * @param None
+ * @retval None
+ */
+void FLASH_LockBank1(void)
+{
+ /* Set the Lock Bit to lock the FPEC and the CR of Bank1 */
+ FLASH->CR |= CR_LOCK_Set;
+}
+
+#ifdef STM32F10X_XL
+/**
+ * @brief Locks the FLASH Bank2 Program Erase Controller.
+ * @note This function can be used only for STM32F10X_XL density devices.
+ * @param None
+ * @retval None
+ */
+void FLASH_LockBank2(void)
+{
+ /* Set the Lock Bit to lock the FPEC and the CR of Bank2 */
+ FLASH->CR2 |= CR_LOCK_Set;
+}
+#endif /* STM32F10X_XL */
+
+/**
+ * @brief Erases a specified FLASH page.
+ * @note This function can be used for all STM32F10x devices.
+ * @param Page_Address: The page address to be erased.
+ * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
+ */
+FLASH_Status FLASH_ErasePage(uint32_t Page_Address)
+{
+ FLASH_Status status = FLASH_COMPLETE;
+ /* Check the parameters */
+ assert_param(IS_FLASH_ADDRESS(Page_Address));
+
+#ifdef STM32F10X_XL
+ if(Page_Address < FLASH_BANK1_END_ADDRESS)
+ {
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank1Operation(EraseTimeout);
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to erase the page */
+ FLASH->CR|= CR_PER_Set;
+ FLASH->AR = Page_Address;
+ FLASH->CR|= CR_STRT_Set;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank1Operation(EraseTimeout);
+
+ /* Disable the PER Bit */
+ FLASH->CR &= CR_PER_Reset;
+ }
+ }
+ else
+ {
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank2Operation(EraseTimeout);
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to erase the page */
+ FLASH->CR2|= CR_PER_Set;
+ FLASH->AR2 = Page_Address;
+ FLASH->CR2|= CR_STRT_Set;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank2Operation(EraseTimeout);
+
+ /* Disable the PER Bit */
+ FLASH->CR2 &= CR_PER_Reset;
+ }
+ }
+#else
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(EraseTimeout);
+
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to erase the page */
+ FLASH->CR|= CR_PER_Set;
+ FLASH->AR = Page_Address;
+ FLASH->CR|= CR_STRT_Set;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(EraseTimeout);
+
+ /* Disable the PER Bit */
+ FLASH->CR &= CR_PER_Reset;
+ }
+#endif /* STM32F10X_XL */
+
+ /* Return the Erase Status */
+ return status;
+}
+
+/**
+ * @brief Erases all FLASH pages.
+ * @note This function can be used for all STM32F10x devices.
+ * @param None
+ * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
+ */
+FLASH_Status FLASH_EraseAllPages(void)
+{
+ FLASH_Status status = FLASH_COMPLETE;
+
+#ifdef STM32F10X_XL
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank1Operation(EraseTimeout);
+
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to erase all pages */
+ FLASH->CR |= CR_MER_Set;
+ FLASH->CR |= CR_STRT_Set;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank1Operation(EraseTimeout);
+
+ /* Disable the MER Bit */
+ FLASH->CR &= CR_MER_Reset;
+ }
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to erase all pages */
+ FLASH->CR2 |= CR_MER_Set;
+ FLASH->CR2 |= CR_STRT_Set;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank2Operation(EraseTimeout);
+
+ /* Disable the MER Bit */
+ FLASH->CR2 &= CR_MER_Reset;
+ }
+#else
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(EraseTimeout);
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to erase all pages */
+ FLASH->CR |= CR_MER_Set;
+ FLASH->CR |= CR_STRT_Set;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(EraseTimeout);
+
+ /* Disable the MER Bit */
+ FLASH->CR &= CR_MER_Reset;
+ }
+#endif /* STM32F10X_XL */
+
+ /* Return the Erase Status */
+ return status;
+}
+
+/**
+ * @brief Erases all Bank1 FLASH pages.
+ * @note This function can be used for all STM32F10x devices.
+ * - For STM32F10X_XL devices this function erases all Bank1 pages.
+ * - For all other devices it erases all Bank1 pages and it is equivalent
+ * to FLASH_EraseAllPages function.
+ * @param None
+ * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
+ */
+FLASH_Status FLASH_EraseAllBank1Pages(void)
+{
+ FLASH_Status status = FLASH_COMPLETE;
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank1Operation(EraseTimeout);
+
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to erase all pages */
+ FLASH->CR |= CR_MER_Set;
+ FLASH->CR |= CR_STRT_Set;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank1Operation(EraseTimeout);
+
+ /* Disable the MER Bit */
+ FLASH->CR &= CR_MER_Reset;
+ }
+ /* Return the Erase Status */
+ return status;
+}
+
+#ifdef STM32F10X_XL
+/**
+ * @brief Erases all Bank2 FLASH pages.
+ * @note This function can be used only for STM32F10x_XL density devices.
+ * @param None
+ * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
+ */
+FLASH_Status FLASH_EraseAllBank2Pages(void)
+{
+ FLASH_Status status = FLASH_COMPLETE;
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank2Operation(EraseTimeout);
+
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to erase all pages */
+ FLASH->CR2 |= CR_MER_Set;
+ FLASH->CR2 |= CR_STRT_Set;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank2Operation(EraseTimeout);
+
+ /* Disable the MER Bit */
+ FLASH->CR2 &= CR_MER_Reset;
+ }
+ /* Return the Erase Status */
+ return status;
+}
+#endif /* STM32F10X_XL */
+
+/**
+ * @brief Erases the FLASH option bytes.
+ * @note This functions erases all option bytes except the Read protection (RDP).
+ * @note This function can be used for all STM32F10x devices.
+ * @param None
+ * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
+ */
+FLASH_Status FLASH_EraseOptionBytes(void)
+{
+ uint16_t rdptmp = RDP_Key;
+
+ FLASH_Status status = FLASH_COMPLETE;
+
+ /* Get the actual read protection Option Byte value */
+ if(FLASH_GetReadOutProtectionStatus() != RESET)
+ {
+ rdptmp = 0x00;
+ }
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(EraseTimeout);
+ if(status == FLASH_COMPLETE)
+ {
+ /* Authorize the small information block programming */
+ FLASH->OPTKEYR = FLASH_KEY1;
+ FLASH->OPTKEYR = FLASH_KEY2;
+
+ /* if the previous operation is completed, proceed to erase the option bytes */
+ FLASH->CR |= CR_OPTER_Set;
+ FLASH->CR |= CR_STRT_Set;
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(EraseTimeout);
+
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the erase operation is completed, disable the OPTER Bit */
+ FLASH->CR &= CR_OPTER_Reset;
+
+ /* Enable the Option Bytes Programming operation */
+ FLASH->CR |= CR_OPTPG_Set;
+ /* Restore the last read protection Option Byte value */
+ OB->RDP = (uint16_t)rdptmp;
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+
+ if(status != FLASH_TIMEOUT)
+ {
+ /* if the program operation is completed, disable the OPTPG Bit */
+ FLASH->CR &= CR_OPTPG_Reset;
+ }
+ }
+ else
+ {
+ if (status != FLASH_TIMEOUT)
+ {
+ /* Disable the OPTPG Bit */
+ FLASH->CR &= CR_OPTPG_Reset;
+ }
+ }
+ }
+ /* Return the erase status */
+ return status;
+}
+
+/**
+ * @brief Programs a word at a specified address.
+ * @note This function can be used for all STM32F10x devices.
+ * @param Address: specifies the address to be programmed.
+ * @param Data: specifies the data to be programmed.
+ * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
+ */
+FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data)
+{
+ FLASH_Status status = FLASH_COMPLETE;
+ __IO uint32_t tmp = 0;
+
+ /* Check the parameters */
+ assert_param(IS_FLASH_ADDRESS(Address));
+
+#ifdef STM32F10X_XL
+ if(Address < FLASH_BANK1_END_ADDRESS - 2)
+ {
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank1Operation(ProgramTimeout);
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to program the new first
+ half word */
+ FLASH->CR |= CR_PG_Set;
+
+ *(__IO uint16_t*)Address = (uint16_t)Data;
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to program the new second
+ half word */
+ tmp = Address + 2;
+
+ *(__IO uint16_t*) tmp = Data >> 16;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+
+ /* Disable the PG Bit */
+ FLASH->CR &= CR_PG_Reset;
+ }
+ else
+ {
+ /* Disable the PG Bit */
+ FLASH->CR &= CR_PG_Reset;
+ }
+ }
+ }
+ else if(Address == (FLASH_BANK1_END_ADDRESS - 1))
+ {
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank1Operation(ProgramTimeout);
+
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to program the new first
+ half word */
+ FLASH->CR |= CR_PG_Set;
+
+ *(__IO uint16_t*)Address = (uint16_t)Data;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank1Operation(ProgramTimeout);
+
+ /* Disable the PG Bit */
+ FLASH->CR &= CR_PG_Reset;
+ }
+ else
+ {
+ /* Disable the PG Bit */
+ FLASH->CR &= CR_PG_Reset;
+ }
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank2Operation(ProgramTimeout);
+
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to program the new second
+ half word */
+ FLASH->CR2 |= CR_PG_Set;
+ tmp = Address + 2;
+
+ *(__IO uint16_t*) tmp = Data >> 16;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank2Operation(ProgramTimeout);
+
+ /* Disable the PG Bit */
+ FLASH->CR2 &= CR_PG_Reset;
+ }
+ else
+ {
+ /* Disable the PG Bit */
+ FLASH->CR2 &= CR_PG_Reset;
+ }
+ }
+ else
+ {
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank2Operation(ProgramTimeout);
+
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to program the new first
+ half word */
+ FLASH->CR2 |= CR_PG_Set;
+
+ *(__IO uint16_t*)Address = (uint16_t)Data;
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank2Operation(ProgramTimeout);
+
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to program the new second
+ half word */
+ tmp = Address + 2;
+
+ *(__IO uint16_t*) tmp = Data >> 16;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank2Operation(ProgramTimeout);
+
+ /* Disable the PG Bit */
+ FLASH->CR2 &= CR_PG_Reset;
+ }
+ else
+ {
+ /* Disable the PG Bit */
+ FLASH->CR2 &= CR_PG_Reset;
+ }
+ }
+ }
+#else
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to program the new first
+ half word */
+ FLASH->CR |= CR_PG_Set;
+
+ *(__IO uint16_t*)Address = (uint16_t)Data;
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to program the new second
+ half word */
+ tmp = Address + 2;
+
+ *(__IO uint16_t*) tmp = Data >> 16;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+
+ /* Disable the PG Bit */
+ FLASH->CR &= CR_PG_Reset;
+ }
+ else
+ {
+ /* Disable the PG Bit */
+ FLASH->CR &= CR_PG_Reset;
+ }
+ }
+#endif /* STM32F10X_XL */
+
+ /* Return the Program Status */
+ return status;
+}
+
+/**
+ * @brief Programs a half word at a specified address.
+ * @note This function can be used for all STM32F10x devices.
+ * @param Address: specifies the address to be programmed.
+ * @param Data: specifies the data to be programmed.
+ * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
+ */
+FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
+{
+ FLASH_Status status = FLASH_COMPLETE;
+ /* Check the parameters */
+ assert_param(IS_FLASH_ADDRESS(Address));
+
+#ifdef STM32F10X_XL
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+
+ if(Address < FLASH_BANK1_END_ADDRESS)
+ {
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to program the new data */
+ FLASH->CR |= CR_PG_Set;
+
+ *(__IO uint16_t*)Address = Data;
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank1Operation(ProgramTimeout);
+
+ /* Disable the PG Bit */
+ FLASH->CR &= CR_PG_Reset;
+ }
+ }
+ else
+ {
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to program the new data */
+ FLASH->CR2 |= CR_PG_Set;
+
+ *(__IO uint16_t*)Address = Data;
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastBank2Operation(ProgramTimeout);
+
+ /* Disable the PG Bit */
+ FLASH->CR2 &= CR_PG_Reset;
+ }
+ }
+#else
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the previous operation is completed, proceed to program the new data */
+ FLASH->CR |= CR_PG_Set;
+
+ *(__IO uint16_t*)Address = Data;
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+
+ /* Disable the PG Bit */
+ FLASH->CR &= CR_PG_Reset;
+ }
+#endif /* STM32F10X_XL */
+
+ /* Return the Program Status */
+ return status;
+}
+
+/**
+ * @brief Programs a half word at a specified Option Byte Data address.
+ * @note This function can be used for all STM32F10x devices.
+ * @param Address: specifies the address to be programmed.
+ * This parameter can be 0x1FFFF804 or 0x1FFFF806.
+ * @param Data: specifies the data to be programmed.
+ * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
+ */
+FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data)
+{
+ FLASH_Status status = FLASH_COMPLETE;
+ /* Check the parameters */
+ assert_param(IS_OB_DATA_ADDRESS(Address));
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+
+ if(status == FLASH_COMPLETE)
+ {
+ /* Authorize the small information block programming */
+ FLASH->OPTKEYR = FLASH_KEY1;
+ FLASH->OPTKEYR = FLASH_KEY2;
+ /* Enables the Option Bytes Programming operation */
+ FLASH->CR |= CR_OPTPG_Set;
+ *(__IO uint16_t*)Address = Data;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+ if(status != FLASH_TIMEOUT)
+ {
+ /* if the program operation is completed, disable the OPTPG Bit */
+ FLASH->CR &= CR_OPTPG_Reset;
+ }
+ }
+ /* Return the Option Byte Data Program Status */
+ return status;
+}
+
+/**
+ * @brief Write protects the desired pages
+ * @note This function can be used for all STM32F10x devices.
+ * @param FLASH_Pages: specifies the address of the pages to be write protected.
+ * This parameter can be:
+ * @arg For @b STM32_Low-density_devices: value between FLASH_WRProt_Pages0to3 and FLASH_WRProt_Pages28to31
+ * @arg For @b STM32_Medium-density_devices: value between FLASH_WRProt_Pages0to3
+ * and FLASH_WRProt_Pages124to127
+ * @arg For @b STM32_High-density_devices: value between FLASH_WRProt_Pages0to1 and
+ * FLASH_WRProt_Pages60to61 or FLASH_WRProt_Pages62to255
+ * @arg For @b STM32_Connectivity_line_devices: value between FLASH_WRProt_Pages0to1 and
+ * FLASH_WRProt_Pages60to61 or FLASH_WRProt_Pages62to127
+ * @arg For @b STM32_XL-density_devices: value between FLASH_WRProt_Pages0to1 and
+ * FLASH_WRProt_Pages60to61 or FLASH_WRProt_Pages62to511
+ * @arg FLASH_WRProt_AllPages
+ * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
+ */
+FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages)
+{
+ uint16_t WRP0_Data = 0xFFFF, WRP1_Data = 0xFFFF, WRP2_Data = 0xFFFF, WRP3_Data = 0xFFFF;
+
+ FLASH_Status status = FLASH_COMPLETE;
+
+ /* Check the parameters */
+ assert_param(IS_FLASH_WRPROT_PAGE(FLASH_Pages));
+
+ FLASH_Pages = (uint32_t)(~FLASH_Pages);
+ WRP0_Data = (uint16_t)(FLASH_Pages & WRP0_Mask);
+ WRP1_Data = (uint16_t)((FLASH_Pages & WRP1_Mask) >> 8);
+ WRP2_Data = (uint16_t)((FLASH_Pages & WRP2_Mask) >> 16);
+ WRP3_Data = (uint16_t)((FLASH_Pages & WRP3_Mask) >> 24);
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+
+ if(status == FLASH_COMPLETE)
+ {
+ /* Authorizes the small information block programming */
+ FLASH->OPTKEYR = FLASH_KEY1;
+ FLASH->OPTKEYR = FLASH_KEY2;
+ FLASH->CR |= CR_OPTPG_Set;
+ if(WRP0_Data != 0xFF)
+ {
+ OB->WRP0 = WRP0_Data;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+ }
+ if((status == FLASH_COMPLETE) && (WRP1_Data != 0xFF))
+ {
+ OB->WRP1 = WRP1_Data;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+ }
+ if((status == FLASH_COMPLETE) && (WRP2_Data != 0xFF))
+ {
+ OB->WRP2 = WRP2_Data;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+ }
+
+ if((status == FLASH_COMPLETE)&& (WRP3_Data != 0xFF))
+ {
+ OB->WRP3 = WRP3_Data;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+ }
+
+ if(status != FLASH_TIMEOUT)
+ {
+ /* if the program operation is completed, disable the OPTPG Bit */
+ FLASH->CR &= CR_OPTPG_Reset;
+ }
+ }
+ /* Return the write protection operation Status */
+ return status;
+}
+
+/**
+ * @brief Enables or disables the read out protection.
+ * @note If the user has already programmed the other option bytes before calling
+ * this function, he must re-program them since this function erases all option bytes.
+ * @note This function can be used for all STM32F10x devices.
+ * @param Newstate: new state of the ReadOut Protection.
+ * This parameter can be: ENABLE or DISABLE.
+ * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
+ */
+FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState)
+{
+ FLASH_Status status = FLASH_COMPLETE;
+ /* Check the parameters */
+ assert_param(IS_FUNCTIONAL_STATE(NewState));
+ status = FLASH_WaitForLastOperation(EraseTimeout);
+ if(status == FLASH_COMPLETE)
+ {
+ /* Authorizes the small information block programming */
+ FLASH->OPTKEYR = FLASH_KEY1;
+ FLASH->OPTKEYR = FLASH_KEY2;
+ FLASH->CR |= CR_OPTER_Set;
+ FLASH->CR |= CR_STRT_Set;
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(EraseTimeout);
+ if(status == FLASH_COMPLETE)
+ {
+ /* if the erase operation is completed, disable the OPTER Bit */
+ FLASH->CR &= CR_OPTER_Reset;
+ /* Enable the Option Bytes Programming operation */
+ FLASH->CR |= CR_OPTPG_Set;
+ if(NewState != DISABLE)
+ {
+ OB->RDP = 0x00;
+ }
+ else
+ {
+ OB->RDP = RDP_Key;
+ }
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(EraseTimeout);
+
+ if(status != FLASH_TIMEOUT)
+ {
+ /* if the program operation is completed, disable the OPTPG Bit */
+ FLASH->CR &= CR_OPTPG_Reset;
+ }
+ }
+ else
+ {
+ if(status != FLASH_TIMEOUT)
+ {
+ /* Disable the OPTER Bit */
+ FLASH->CR &= CR_OPTER_Reset;
+ }
+ }
+ }
+ /* Return the protection operation Status */
+ return status;
+}
+
+/**
+ * @brief Programs the FLASH User Option Byte: IWDG_SW / RST_STOP / RST_STDBY.
+ * @note This function can be used for all STM32F10x devices.
+ * @param OB_IWDG: Selects the IWDG mode
+ * This parameter can be one of the following values:
+ * @arg OB_IWDG_SW: Software IWDG selected
+ * @arg OB_IWDG_HW: Hardware IWDG selected
+ * @param OB_STOP: Reset event when entering STOP mode.
+ * This parameter can be one of the following values:
+ * @arg OB_STOP_NoRST: No reset generated when entering in STOP
+ * @arg OB_STOP_RST: Reset generated when entering in STOP
+ * @param OB_STDBY: Reset event when entering Standby mode.
+ * This parameter can be one of the following values:
+ * @arg OB_STDBY_NoRST: No reset generated when entering in STANDBY
+ * @arg OB_STDBY_RST: Reset generated when entering in STANDBY
+ * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
+ */
+FLASH_Status FLASH_UserOptionByteConfig(uint16_t OB_IWDG, uint16_t OB_STOP, uint16_t OB_STDBY)
+{
+ FLASH_Status status = FLASH_COMPLETE;
+
+ /* Check the parameters */
+ assert_param(IS_OB_IWDG_SOURCE(OB_IWDG));
+ assert_param(IS_OB_STOP_SOURCE(OB_STOP));
+ assert_param(IS_OB_STDBY_SOURCE(OB_STDBY));
+
+ /* Authorize the small information block programming */
+ FLASH->OPTKEYR = FLASH_KEY1;
+ FLASH->OPTKEYR = FLASH_KEY2;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+
+ if(status == FLASH_COMPLETE)
+ {
+ /* Enable the Option Bytes Programming operation */
+ FLASH->CR |= CR_OPTPG_Set;
+
+ OB->USER = OB_IWDG | (uint16_t)(OB_STOP | (uint16_t)(OB_STDBY | ((uint16_t)0xF8)));
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+ if(status != FLASH_TIMEOUT)
+ {
+ /* if the program operation is completed, disable the OPTPG Bit */
+ FLASH->CR &= CR_OPTPG_Reset;
+ }
+ }
+ /* Return the Option Byte program Status */
+ return status;
+}
+
+#ifdef STM32F10X_XL
+/**
+ * @brief Configures to boot from Bank1 or Bank2.
+ * @note This function can be used only for STM32F10x_XL density devices.
+ * @param FLASH_BOOT: select the FLASH Bank to boot from.
+ * This parameter can be one of the following values:
+ * @arg FLASH_BOOT_Bank1: At startup, if boot pins are set in boot from user Flash
+ * position and this parameter is selected the device will boot from Bank1(Default).
+ * @arg FLASH_BOOT_Bank2: At startup, if boot pins are set in boot from user Flash
+ * position and this parameter is selected the device will boot from Bank2 or Bank1,
+ * depending on the activation of the bank. The active banks are checked in
+ * the following order: Bank2, followed by Bank1.
+ * The active bank is recognized by the value programmed at the base address
+ * of the respective bank (corresponding to the initial stack pointer value
+ * in the interrupt vector table).
+ * For more information, please refer to AN2606 from www.st.com.
+ * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
+ */
+FLASH_Status FLASH_BootConfig(uint16_t FLASH_BOOT)
+{
+ FLASH_Status status = FLASH_COMPLETE;
+ assert_param(IS_FLASH_BOOT(FLASH_BOOT));
+ /* Authorize the small information block programming */
+ FLASH->OPTKEYR = FLASH_KEY1;
+ FLASH->OPTKEYR = FLASH_KEY2;
+
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+
+ if(status == FLASH_COMPLETE)
+ {
+ /* Enable the Option Bytes Programming operation */
+ FLASH->CR |= CR_OPTPG_Set;
+
+ if(FLASH_BOOT == FLASH_BOOT_Bank1)
+ {
+ OB->USER |= OB_USER_BFB2;
+ }
+ else
+ {
+ OB->USER &= (uint16_t)(~(uint16_t)(OB_USER_BFB2));
+ }
+ /* Wait for last operation to be completed */
+ status = FLASH_WaitForLastOperation(ProgramTimeout);
+ if(status != FLASH_TIMEOUT)
+ {
+ /* if the program operation is completed, disable the OPTPG Bit */
+ FLASH->CR &= CR_OPTPG_Reset;
+ }
+ }
+ /* Return the Option Byte program Status */
+ return status;
+}
+#endif /* STM32F10X_XL */
+
+/**
+ * @brief Returns the FLASH User Option Bytes values.
+ * @note This function can be used for all STM32F10x devices.
+ * @param None
+ * @retval The FLASH User Option Bytes values:IWDG_SW(Bit0), RST_STOP(Bit1)
+ * and RST_STDBY(Bit2).
+ */
+uint32_t FLASH_GetUserOptionByte(void)
+{
+ /* Return the User Option Byte */
+ return (uint32_t)(FLASH->OBR >> 2);
+}
+
+/**
+ * @brief Returns the FLASH Write Protection Option Bytes Register value.
+ * @note This function can be used for all STM32F10x devices.
+ * @param None
+ * @retval The FLASH Write Protection Option Bytes Register value
+ */
+uint32_t FLASH_GetWriteProtectionOptionByte(void)
+{
+ /* Return the Flash write protection Register value */
+ return (uint32_t)(FLASH->WRPR);
+}
+
+/**
+ * @brief Checks whether the FLASH Read Out Protection Status is set or not.
+ * @note This function can be used for all STM32F10x devices.
+ * @param None
+ * @retval FLASH ReadOut Protection Status(SET or RESET)
+ */
+FlagStatus FLASH_GetReadOutProtectionStatus(void)
+{
+ FlagStatus readoutstatus = RESET;
+ if ((FLASH->OBR & RDPRT_Mask) != (uint32_t)RESET)
+ {
+ readoutstatus = SET;
+ }
+ else
+ {
+ readoutstatus = RESET;
+ }
+ return readoutstatus;
+}
+
+/**
+ * @brief Checks whether the FLASH Prefetch Buffer status is set or not.
+ * @note This function can be used for all STM32F10x devices.
+ * @param None
+ * @retval FLASH Prefetch Buffer Status (SET or RESET).
+ */
+FlagStatus FLASH_GetPrefetchBufferStatus(void)
+{
+ FlagStatus bitstatus = RESET;
+
+ if ((FLASH->ACR & ACR_PRFTBS_Mask) != (uint32_t)RESET)
+ {
+ bitstatus = SET;
+ }
+ else
+ {
+ bitstatus = RESET;
+ }
+ /* Return the new state of FLASH Prefetch Buffer Status (SET or RESET) */
+ return bitstatus;
+}
+
+/**
+ * @brief Enables or disables the specified FLASH interrupts.
+ * @note This function can be used for all STM32F10x devices.
+ * - For STM32F10X_XL devices, enables or disables the specified FLASH interrupts
+ for Bank1 and Bank2.
+ * - For other devices it enables or disables the specified FLASH interrupts for Bank1.
+ * @param FLASH_IT: specifies the FLASH interrupt sources to be enabled or disabled.
+ * This parameter can be any combination of the following values:
+ * @arg FLASH_IT_ERROR: FLASH Error Interrupt
+ * @arg FLASH_IT_EOP: FLASH end of operation Interrupt
+ * @param NewState: new state of the specified Flash interrupts.
+ * This parameter can be: ENABLE or DISABLE.
+ * @retval None
+ */
+void FLASH_ITConfig(uint32_t FLASH_IT, FunctionalState NewState)
+{
+#ifdef STM32F10X_XL
+ /* Check the parameters */
+ assert_param(IS_FLASH_IT(FLASH_IT));
+ assert_param(IS_FUNCTIONAL_STATE(NewState));
+
+ if((FLASH_IT & 0x80000000) != 0x0)
+ {
+ if(NewState != DISABLE)
+ {
+ /* Enable the interrupt sources */
+ FLASH->CR2 |= (FLASH_IT & 0x7FFFFFFF);
+ }
+ else
+ {
+ /* Disable the interrupt sources */
+ FLASH->CR2 &= ~(uint32_t)(FLASH_IT & 0x7FFFFFFF);
+ }
+ }
+ else
+ {
+ if(NewState != DISABLE)
+ {
+ /* Enable the interrupt sources */
+ FLASH->CR |= FLASH_IT;
+ }
+ else
+ {
+ /* Disable the interrupt sources */
+ FLASH->CR &= ~(uint32_t)FLASH_IT;
+ }
+ }
+#else
+ /* Check the parameters */
+ assert_param(IS_FLASH_IT(FLASH_IT));
+ assert_param(IS_FUNCTIONAL_STATE(NewState));
+
+ if(NewState != DISABLE)
+ {
+ /* Enable the interrupt sources */
+ FLASH->CR |= FLASH_IT;
+ }
+ else
+ {
+ /* Disable the interrupt sources */
+ FLASH->CR &= ~(uint32_t)FLASH_IT;
+ }
+#endif /* STM32F10X_XL */
+}
+
+/**
+ * @brief Checks whether the specified FLASH flag is set or not.
+ * @note This function can be used for all STM32F10x devices.
+ * - For STM32F10X_XL devices, this function checks whether the specified
+ * Bank1 or Bank2 flag is set or not.
+ * - For other devices, it checks whether the specified Bank1 flag is
+ * set or not.
+ * @param FLASH_FLAG: specifies the FLASH flag to check.
+ * This parameter can be one of the following values:
+ * @arg FLASH_FLAG_BSY: FLASH Busy flag
+ * @arg FLASH_FLAG_PGERR: FLASH Program error flag
+ * @arg FLASH_FLAG_WRPRTERR: FLASH Write protected error flag
+ * @arg FLASH_FLAG_EOP: FLASH End of Operation flag
+ * @arg FLASH_FLAG_OPTERR: FLASH Option Byte error flag
+ * @retval The new state of FLASH_FLAG (SET or RESET).
+ */
+FlagStatus FLASH_GetFlagStatus(uint32_t FLASH_FLAG)
+{
+ FlagStatus bitstatus = RESET;
+
+#ifdef STM32F10X_XL
+ /* Check the parameters */
+ assert_param(IS_FLASH_GET_FLAG(FLASH_FLAG)) ;
+ if(FLASH_FLAG == FLASH_FLAG_OPTERR)
+ {
+ if((FLASH->OBR & FLASH_FLAG_OPTERR) != (uint32_t)RESET)
+ {
+ bitstatus = SET;
+ }
+ else
+ {
+ bitstatus = RESET;
+ }
+ }
+ else
+ {
+ if((FLASH_FLAG & 0x80000000) != 0x0)
+ {
+ if((FLASH->SR2 & FLASH_FLAG) != (uint32_t)RESET)
+ {
+ bitstatus = SET;
+ }
+ else
+ {
+ bitstatus = RESET;
+ }
+ }
+ else
+ {
+ if((FLASH->SR & FLASH_FLAG) != (uint32_t)RESET)
+ {
+ bitstatus = SET;
+ }
+ else
+ {
+ bitstatus = RESET;
+ }
+ }
+ }
+#else
+ /* Check the parameters */
+ assert_param(IS_FLASH_GET_FLAG(FLASH_FLAG)) ;
+ if(FLASH_FLAG == FLASH_FLAG_OPTERR)
+ {
+ if((FLASH->OBR & FLASH_FLAG_OPTERR) != (uint32_t)RESET)
+ {
+ bitstatus = SET;
+ }
+ else
+ {
+ bitstatus = RESET;
+ }
+ }
+ else
+ {
+ if((FLASH->SR & FLASH_FLAG) != (uint32_t)RESET)
+ {
+ bitstatus = SET;
+ }
+ else
+ {
+ bitstatus = RESET;
+ }
+ }
+#endif /* STM32F10X_XL */
+
+ /* Return the new state of FLASH_FLAG (SET or RESET) */
+ return bitstatus;
+}
+
+/**
+ * @brief Clears the FLASH's pending flags.
+ * @note This function can be used for all STM32F10x devices.
+ * - For STM32F10X_XL devices, this function clears Bank1 or Bank2’s pending flags
+ * - For other devices, it clears Bank1’s pending flags.
+ * @param FLASH_FLAG: specifies the FLASH flags to clear.
+ * This parameter can be any combination of the following values:
+ * @arg FLASH_FLAG_PGERR: FLASH Program error flag
+ * @arg FLASH_FLAG_WRPRTERR: FLASH Write protected error flag
+ * @arg FLASH_FLAG_EOP: FLASH End of Operation flag
+ * @retval None
+ */
+void FLASH_ClearFlag(uint32_t FLASH_FLAG)
+{
+#ifdef STM32F10X_XL
+ /* Check the parameters */
+ assert_param(IS_FLASH_CLEAR_FLAG(FLASH_FLAG)) ;
+
+ if((FLASH_FLAG & 0x80000000) != 0x0)
+ {
+ /* Clear the flags */
+ FLASH->SR2 = FLASH_FLAG;
+ }
+ else
+ {
+ /* Clear the flags */
+ FLASH->SR = FLASH_FLAG;
+ }
+
+#else
+ /* Check the parameters */
+ assert_param(IS_FLASH_CLEAR_FLAG(FLASH_FLAG)) ;
+
+ /* Clear the flags */
+ FLASH->SR = FLASH_FLAG;
+#endif /* STM32F10X_XL */
+}
+
+/**
+ * @brief Returns the FLASH Status.
+ * @note This function can be used for all STM32F10x devices, it is equivalent
+ * to FLASH_GetBank1Status function.
+ * @param None
+ * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP or FLASH_COMPLETE
+ */
+FLASH_Status FLASH_GetStatus(void)
+{
+ FLASH_Status flashstatus = FLASH_COMPLETE;
+
+ if((FLASH->SR & FLASH_FLAG_BSY) == FLASH_FLAG_BSY)
+ {
+ flashstatus = FLASH_BUSY;
+ }
+ else
+ {
+ if((FLASH->SR & FLASH_FLAG_PGERR) != 0)
+ {
+ flashstatus = FLASH_ERROR_PG;
+ }
+ else
+ {
+ if((FLASH->SR & FLASH_FLAG_WRPRTERR) != 0 )
+ {
+ flashstatus = FLASH_ERROR_WRP;
+ }
+ else
+ {
+ flashstatus = FLASH_COMPLETE;
+ }
+ }
+ }
+ /* Return the Flash Status */
+ return flashstatus;
+}
+
+/**
+ * @brief Returns the FLASH Bank1 Status.
+ * @note This function can be used for all STM32F10x devices, it is equivalent
+ * to FLASH_GetStatus function.
+ * @param None
+ * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP or FLASH_COMPLETE
+ */
+FLASH_Status FLASH_GetBank1Status(void)
+{
+ FLASH_Status flashstatus = FLASH_COMPLETE;
+
+ if((FLASH->SR & FLASH_FLAG_BANK1_BSY) == FLASH_FLAG_BSY)
+ {
+ flashstatus = FLASH_BUSY;
+ }
+ else
+ {
+ if((FLASH->SR & FLASH_FLAG_BANK1_PGERR) != 0)
+ {
+ flashstatus = FLASH_ERROR_PG;
+ }
+ else
+ {
+ if((FLASH->SR & FLASH_FLAG_BANK1_WRPRTERR) != 0 )
+ {
+ flashstatus = FLASH_ERROR_WRP;
+ }
+ else
+ {
+ flashstatus = FLASH_COMPLETE;
+ }
+ }
+ }
+ /* Return the Flash Status */
+ return flashstatus;
+}
+
+#ifdef STM32F10X_XL
+/**
+ * @brief Returns the FLASH Bank2 Status.
+ * @note This function can be used for STM32F10x_XL density devices.
+ * @param None
+ * @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP or FLASH_COMPLETE
+ */
+FLASH_Status FLASH_GetBank2Status(void)
+{
+ FLASH_Status flashstatus = FLASH_COMPLETE;
+
+ if((FLASH->SR2 & (FLASH_FLAG_BANK2_BSY & 0x7FFFFFFF)) == (FLASH_FLAG_BANK2_BSY & 0x7FFFFFFF))
+ {
+ flashstatus = FLASH_BUSY;
+ }
+ else
+ {
+ if((FLASH->SR2 & (FLASH_FLAG_BANK2_PGERR & 0x7FFFFFFF)) != 0)
+ {
+ flashstatus = FLASH_ERROR_PG;
+ }
+ else
+ {
+ if((FLASH->SR2 & (FLASH_FLAG_BANK2_WRPRTERR & 0x7FFFFFFF)) != 0 )
+ {
+ flashstatus = FLASH_ERROR_WRP;
+ }
+ else
+ {
+ flashstatus = FLASH_COMPLETE;
+ }
+ }
+ }
+ /* Return the Flash Status */
+ return flashstatus;
+}
+#endif /* STM32F10X_XL */
+/**
+ * @brief Waits for a Flash operation to complete or a TIMEOUT to occur.
+ * @note This function can be used for all STM32F10x devices,
+ * it is equivalent to FLASH_WaitForLastBank1Operation.
+ * - For STM32F10X_XL devices this function waits for a Bank1 Flash operation
+ * to complete or a TIMEOUT to occur.
+ * - For all other devices it waits for a Flash operation to complete
+ * or a TIMEOUT to occur.
+ * @param Timeout: FLASH programming Timeout
+ * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
+ */
+FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout)
+{
+ FLASH_Status status = FLASH_COMPLETE;
+
+ /* Check for the Flash Status */
+ status = FLASH_GetBank1Status();
+ /* Wait for a Flash operation to complete or a TIMEOUT to occur */
+ while((status == FLASH_BUSY) && (Timeout != 0x00))
+ {
+ status = FLASH_GetBank1Status();
+ Timeout--;
+ }
+ if(Timeout == 0x00 )
+ {
+ status = FLASH_TIMEOUT;
+ }
+ /* Return the operation status */
+ return status;
+}
+
+/**
+ * @brief Waits for a Flash operation on Bank1 to complete or a TIMEOUT to occur.
+ * @note This function can be used for all STM32F10x devices,
+ * it is equivalent to FLASH_WaitForLastOperation.
+ * @param Timeout: FLASH programming Timeout
+ * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
+ */
+FLASH_Status FLASH_WaitForLastBank1Operation(uint32_t Timeout)
+{
+ FLASH_Status status = FLASH_COMPLETE;
+
+ /* Check for the Flash Status */
+ status = FLASH_GetBank1Status();
+ /* Wait for a Flash operation to complete or a TIMEOUT to occur */
+ while((status == FLASH_FLAG_BANK1_BSY) && (Timeout != 0x00))
+ {
+ status = FLASH_GetBank1Status();
+ Timeout--;
+ }
+ if(Timeout == 0x00 )
+ {
+ status = FLASH_TIMEOUT;
+ }
+ /* Return the operation status */
+ return status;
+}
+
+#ifdef STM32F10X_XL
+/**
+ * @brief Waits for a Flash operation on Bank2 to complete or a TIMEOUT to occur.
+ * @note This function can be used only for STM32F10x_XL density devices.
+ * @param Timeout: FLASH programming Timeout
+ * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
+ * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
+ */
+FLASH_Status FLASH_WaitForLastBank2Operation(uint32_t Timeout)
+{
+ FLASH_Status status = FLASH_COMPLETE;
+
+ /* Check for the Flash Status */
+ status = FLASH_GetBank2Status();
+ /* Wait for a Flash operation to complete or a TIMEOUT to occur */
+ while((status == (FLASH_FLAG_BANK2_BSY & 0x7FFFFFFF)) && (Timeout != 0x00))
+ {
+ status = FLASH_GetBank2Status();
+ Timeout--;
+ }
+ if(Timeout == 0x00 )
+ {
+ status = FLASH_TIMEOUT;
+ }
+ /* Return the operation status */
+ return status;
+}
+#endif /* STM32F10X_XL */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
diff --git a/stm_lib/src/stm32f10x_gpio.c b/stm_lib/src/stm32f10x_gpio.c
new file mode 100644
index 00000000..457ff112
--- /dev/null
+++ b/stm_lib/src/stm32f10x_gpio.c
@@ -0,0 +1,650 @@
+/**
+ ******************************************************************************
+ * @file stm32f10x_gpio.c
+ * @author MCD Application Team
+ * @version V3.5.0
+ * @date 11-March-2011
+ * @brief This file provides all the GPIO firmware functions.
+ ******************************************************************************
+ * @attention
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32f10x_tim.h"
+#include "stm32f10x_rcc.h"
+
+/** @addtogroup STM32F10x_StdPeriph_Driver
+ * @{
+ */
+
+/** @defgroup TIM
+ * @brief TIM driver modules
+ * @{
+ */
+
+/** @defgroup TIM_Private_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup TIM_Private_Defines
+ * @{
+ */
+
+/* ---------------------- TIM registers bit mask ------------------------ */
+#define SMCR_ETR_Mask ((uint16_t)0x00FF)
+#define CCMR_Offset ((uint16_t)0x0018)
+#define CCER_CCE_Set ((uint16_t)0x0001)
+#define CCER_CCNE_Set ((uint16_t)0x0004)
+
+/**
+ * @}
+ */
+
+/** @defgroup TIM_Private_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup TIM_Private_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup TIM_Private_FunctionPrototypes
+ * @{
+ */
+
+static void TI1_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection,
+ uint16_t TIM_ICFilter);
+static void TI2_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection,
+ uint16_t TIM_ICFilter);
+static void TI3_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection,
+ uint16_t TIM_ICFilter);
+static void TI4_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection,
+ uint16_t TIM_ICFilter);
+/**
+ * @}
+ */
+
+/** @defgroup TIM_Private_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup TIM_Private_Variables
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup TIM_Private_FunctionPrototypes
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup TIM_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief Deinitializes the TIMx peripheral registers to their default reset values.
+ * @param TIMx: where x can be 1 to 17 to select the TIM peripheral.
+ * @retval None
+ */
+void TIM_DeInit(TIM_TypeDef* TIMx)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+
+ if (TIMx == TIM1)
+ {
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM1, ENABLE);
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM1, DISABLE);
+ }
+ else if (TIMx == TIM2)
+ {
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM2, ENABLE);
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM2, DISABLE);
+ }
+ else if (TIMx == TIM3)
+ {
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3, ENABLE);
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3, DISABLE);
+ }
+ else if (TIMx == TIM4)
+ {
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM4, ENABLE);
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM4, DISABLE);
+ }
+ else if (TIMx == TIM5)
+ {
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM5, ENABLE);
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM5, DISABLE);
+ }
+ else if (TIMx == TIM6)
+ {
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM6, ENABLE);
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM6, DISABLE);
+ }
+ else if (TIMx == TIM7)
+ {
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM7, ENABLE);
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM7, DISABLE);
+ }
+ else if (TIMx == TIM8)
+ {
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM8, ENABLE);
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM8, DISABLE);
+ }
+ else if (TIMx == TIM9)
+ {
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM9, ENABLE);
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM9, DISABLE);
+ }
+ else if (TIMx == TIM10)
+ {
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM10, ENABLE);
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM10, DISABLE);
+ }
+ else if (TIMx == TIM11)
+ {
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM11, ENABLE);
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM11, DISABLE);
+ }
+ else if (TIMx == TIM12)
+ {
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM12, ENABLE);
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM12, DISABLE);
+ }
+ else if (TIMx == TIM13)
+ {
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM13, ENABLE);
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM13, DISABLE);
+ }
+ else if (TIMx == TIM14)
+ {
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM14, ENABLE);
+ RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM14, DISABLE);
+ }
+ else if (TIMx == TIM15)
+ {
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM15, ENABLE);
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM15, DISABLE);
+ }
+ else if (TIMx == TIM16)
+ {
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM16, ENABLE);
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM16, DISABLE);
+ }
+ else
+ {
+ if (TIMx == TIM17)
+ {
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM17, ENABLE);
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM17, DISABLE);
+ }
+ }
+}
+
+/**
+ * @brief Initializes the TIMx Time Base Unit peripheral according to
+ * the specified parameters in the TIM_TimeBaseInitStruct.
+ * @param TIMx: where x can be 1 to 17 to select the TIM peripheral.
+ * @param TIM_TimeBaseInitStruct: pointer to a TIM_TimeBaseInitTypeDef
+ * structure that contains the configuration information for the
+ * specified TIM peripheral.
+ * @retval None
+ */
+void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
+{
+ uint16_t tmpcr1 = 0;
+
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+ assert_param(IS_TIM_COUNTER_MODE(TIM_TimeBaseInitStruct->TIM_CounterMode));
+ assert_param(IS_TIM_CKD_DIV(TIM_TimeBaseInitStruct->TIM_ClockDivision));
+
+ tmpcr1 = TIMx->CR1;
+
+ if((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM2) || (TIMx == TIM3)||
+ (TIMx == TIM4) || (TIMx == TIM5))
+ {
+ /* Select the Counter Mode */
+ tmpcr1 &= (uint16_t)(~((uint16_t)(TIM_CR1_DIR | TIM_CR1_CMS)));
+ tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_CounterMode;
+ }
+
+ if((TIMx != TIM6) && (TIMx != TIM7))
+ {
+ /* Set the clock division */
+ tmpcr1 &= (uint16_t)(~((uint16_t)TIM_CR1_CKD));
+ tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision;
+ }
+
+ TIMx->CR1 = tmpcr1;
+
+ /* Set the Autoreload value */
+ TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ;
+
+ /* Set the Prescaler value */
+ TIMx->PSC = TIM_TimeBaseInitStruct->TIM_Prescaler;
+
+ if ((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM15)|| (TIMx == TIM16) || (TIMx == TIM17))
+ {
+ /* Set the Repetition Counter value */
+ TIMx->RCR = TIM_TimeBaseInitStruct->TIM_RepetitionCounter;
+ }
+
+ /* Generate an update event to reload the Prescaler and the Repetition counter
+ values immediately */
+ TIMx->EGR = TIM_PSCReloadMode_Immediate;
+}
+
+/**
+ * @brief Initializes the TIMx Channel1 according to the specified
+ * parameters in the TIM_OCInitStruct.
+ * @param TIMx: where x can be 1 to 17 except 6 and 7 to select the TIM peripheral.
+ * @param TIM_OCInitStruct: pointer to a TIM_OCInitTypeDef structure
+ * that contains the configuration information for the specified TIM peripheral.
+ * @retval None
+ */
+void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)
+{
+ uint16_t tmpccmrx = 0, tmpccer = 0, tmpcr2 = 0;
+
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST8_PERIPH(TIMx));
+ assert_param(IS_TIM_OC_MODE(TIM_OCInitStruct->TIM_OCMode));
+ assert_param(IS_TIM_OUTPUT_STATE(TIM_OCInitStruct->TIM_OutputState));
+ assert_param(IS_TIM_OC_POLARITY(TIM_OCInitStruct->TIM_OCPolarity));
+ /* Disable the Channel 1: Reset the CC1E Bit */
+ TIMx->CCER &= (uint16_t)(~(uint16_t)TIM_CCER_CC1E);
+ /* Get the TIMx CCER register value */
+ tmpccer = TIMx->CCER;
+ /* Get the TIMx CR2 register value */
+ tmpcr2 = TIMx->CR2;
+
+ /* Get the TIMx CCMR1 register value */
+ tmpccmrx = TIMx->CCMR1;
+
+ /* Reset the Output Compare Mode Bits */
+ tmpccmrx &= (uint16_t)(~((uint16_t)TIM_CCMR1_OC1M));
+ tmpccmrx &= (uint16_t)(~((uint16_t)TIM_CCMR1_CC1S));
+
+ /* Select the Output Compare Mode */
+ tmpccmrx |= TIM_OCInitStruct->TIM_OCMode;
+
+ /* Reset the Output Polarity level */
+ tmpccer &= (uint16_t)(~((uint16_t)TIM_CCER_CC1P));
+ /* Set the Output Compare Polarity */
+ tmpccer |= TIM_OCInitStruct->TIM_OCPolarity;
+
+ /* Set the Output State */
+ tmpccer |= TIM_OCInitStruct->TIM_OutputState;
+
+ if((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM15)||
+ (TIMx == TIM16)|| (TIMx == TIM17))
+ {
+ assert_param(IS_TIM_OUTPUTN_STATE(TIM_OCInitStruct->TIM_OutputNState));
+ assert_param(IS_TIM_OCN_POLARITY(TIM_OCInitStruct->TIM_OCNPolarity));
+ assert_param(IS_TIM_OCNIDLE_STATE(TIM_OCInitStruct->TIM_OCNIdleState));
+ assert_param(IS_TIM_OCIDLE_STATE(TIM_OCInitStruct->TIM_OCIdleState));
+
+ /* Reset the Output N Polarity level */
+ tmpccer &= (uint16_t)(~((uint16_t)TIM_CCER_CC1NP));
+ /* Set the Output N Polarity */
+ tmpccer |= TIM_OCInitStruct->TIM_OCNPolarity;
+
+ /* Reset the Output N State */
+ tmpccer &= (uint16_t)(~((uint16_t)TIM_CCER_CC1NE));
+ /* Set the Output N State */
+ tmpccer |= TIM_OCInitStruct->TIM_OutputNState;
+
+ /* Reset the Output Compare and Output Compare N IDLE State */
+ tmpcr2 &= (uint16_t)(~((uint16_t)TIM_CR2_OIS1));
+ tmpcr2 &= (uint16_t)(~((uint16_t)TIM_CR2_OIS1N));
+
+ /* Set the Output Idle state */
+ tmpcr2 |= TIM_OCInitStruct->TIM_OCIdleState;
+ /* Set the Output N Idle state */
+ tmpcr2 |= TIM_OCInitStruct->TIM_OCNIdleState;
+ }
+ /* Write to TIMx CR2 */
+ TIMx->CR2 = tmpcr2;
+
+ /* Write to TIMx CCMR1 */
+ TIMx->CCMR1 = tmpccmrx;
+
+ /* Set the Capture Compare Register value */
+ TIMx->CCR1 = TIM_OCInitStruct->TIM_Pulse;
+
+ /* Write to TIMx CCER */
+ TIMx->CCER = tmpccer;
+}
+
+/**
+ * @brief Initializes the TIMx Channel2 according to the specified
+ * parameters in the TIM_OCInitStruct.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 9, 12 or 15 to select
+ * the TIM peripheral.
+ * @param TIM_OCInitStruct: pointer to a TIM_OCInitTypeDef structure
+ * that contains the configuration information for the specified TIM peripheral.
+ * @retval None
+ */
+void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)
+{
+ uint16_t tmpccmrx = 0, tmpccer = 0, tmpcr2 = 0;
+
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST6_PERIPH(TIMx));
+ assert_param(IS_TIM_OC_MODE(TIM_OCInitStruct->TIM_OCMode));
+ assert_param(IS_TIM_OUTPUT_STATE(TIM_OCInitStruct->TIM_OutputState));
+ assert_param(IS_TIM_OC_POLARITY(TIM_OCInitStruct->TIM_OCPolarity));
+ /* Disable the Channel 2: Reset the CC2E Bit */
+ TIMx->CCER &= (uint16_t)(~((uint16_t)TIM_CCER_CC2E));
+
+ /* Get the TIMx CCER register value */
+ tmpccer = TIMx->CCER;
+ /* Get the TIMx CR2 register value */
+ tmpcr2 = TIMx->CR2;
+
+ /* Get the TIMx CCMR1 register value */
+ tmpccmrx = TIMx->CCMR1;
+
+ /* Reset the Output Compare mode and Capture/Compare selection Bits */
+ tmpccmrx &= (uint16_t)(~((uint16_t)TIM_CCMR1_OC2M));
+ tmpccmrx &= (uint16_t)(~((uint16_t)TIM_CCMR1_CC2S));
+
+ /* Select the Output Compare Mode */
+ tmpccmrx |= (uint16_t)(TIM_OCInitStruct->TIM_OCMode << 8);
+
+ /* Reset the Output Polarity level */
+ tmpccer &= (uint16_t)(~((uint16_t)TIM_CCER_CC2P));
+ /* Set the Output Compare Polarity */
+ tmpccer |= (uint16_t)(TIM_OCInitStruct->TIM_OCPolarity << 4);
+
+ /* Set the Output State */
+ tmpccer |= (uint16_t)(TIM_OCInitStruct->TIM_OutputState << 4);
+
+ if((TIMx == TIM1) || (TIMx == TIM8))
+ {
+ assert_param(IS_TIM_OUTPUTN_STATE(TIM_OCInitStruct->TIM_OutputNState));
+ assert_param(IS_TIM_OCN_POLARITY(TIM_OCInitStruct->TIM_OCNPolarity));
+ assert_param(IS_TIM_OCNIDLE_STATE(TIM_OCInitStruct->TIM_OCNIdleState));
+ assert_param(IS_TIM_OCIDLE_STATE(TIM_OCInitStruct->TIM_OCIdleState));
+
+ /* Reset the Output N Polarity level */
+ tmpccer &= (uint16_t)(~((uint16_t)TIM_CCER_CC2NP));
+ /* Set the Output N Polarity */
+ tmpccer |= (uint16_t)(TIM_OCInitStruct->TIM_OCNPolarity << 4);
+
+ /* Reset the Output N State */
+ tmpccer &= (uint16_t)(~((uint16_t)TIM_CCER_CC2NE));
+ /* Set the Output N State */
+ tmpccer |= (uint16_t)(TIM_OCInitStruct->TIM_OutputNState << 4);
+
+ /* Reset the Output Compare and Output Compare N IDLE State */
+ tmpcr2 &= (uint16_t)(~((uint16_t)TIM_CR2_OIS2));
+ tmpcr2 &= (uint16_t)(~((uint16_t)TIM_CR2_OIS2N));
+
+ /* Set the Output Idle state */
+ tmpcr2 |= (uint16_t)(TIM_OCInitStruct->TIM_OCIdleState << 2);
+ /* Set the Output N Idle state */
+ tmpcr2 |= (uint16_t)(TIM_OCInitStruct->TIM_OCNIdleState << 2);
+ }
+ /* Write to TIMx CR2 */
+ TIMx->CR2 = tmpcr2;
+
+ /* Write to TIMx CCMR1 */
+ TIMx->CCMR1 = tmpccmrx;
+
+ /* Set the Capture Compare Register value */
+ TIMx->CCR2 = TIM_OCInitStruct->TIM_Pulse;
+
+ /* Write to TIMx CCER */
+ TIMx->CCER = tmpccer;
+}
+
+/**
+ * @brief Initializes the TIMx Channel3 according to the specified
+ * parameters in the TIM_OCInitStruct.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_OCInitStruct: pointer to a TIM_OCInitTypeDef structure
+ * that contains the configuration information for the specified TIM peripheral.
+ * @retval None
+ */
+void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)
+{
+ uint16_t tmpccmrx = 0, tmpccer = 0, tmpcr2 = 0;
+
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_OC_MODE(TIM_OCInitStruct->TIM_OCMode));
+ assert_param(IS_TIM_OUTPUT_STATE(TIM_OCInitStruct->TIM_OutputState));
+ assert_param(IS_TIM_OC_POLARITY(TIM_OCInitStruct->TIM_OCPolarity));
+ /* Disable the Channel 2: Reset the CC2E Bit */
+ TIMx->CCER &= (uint16_t)(~((uint16_t)TIM_CCER_CC3E));
+
+ /* Get the TIMx CCER register value */
+ tmpccer = TIMx->CCER;
+ /* Get the TIMx CR2 register value */
+ tmpcr2 = TIMx->CR2;
+
+ /* Get the TIMx CCMR2 register value */
+ tmpccmrx = TIMx->CCMR2;
+
+ /* Reset the Output Compare mode and Capture/Compare selection Bits */
+ tmpccmrx &= (uint16_t)(~((uint16_t)TIM_CCMR2_OC3M));
+ tmpccmrx &= (uint16_t)(~((uint16_t)TIM_CCMR2_CC3S));
+ /* Select the Output Compare Mode */
+ tmpccmrx |= TIM_OCInitStruct->TIM_OCMode;
+
+ /* Reset the Output Polarity level */
+ tmpccer &= (uint16_t)(~((uint16_t)TIM_CCER_CC3P));
+ /* Set the Output Compare Polarity */
+ tmpccer |= (uint16_t)(TIM_OCInitStruct->TIM_OCPolarity << 8);
+
+ /* Set the Output State */
+ tmpccer |= (uint16_t)(TIM_OCInitStruct->TIM_OutputState << 8);
+
+ if((TIMx == TIM1) || (TIMx == TIM8))
+ {
+ assert_param(IS_TIM_OUTPUTN_STATE(TIM_OCInitStruct->TIM_OutputNState));
+ assert_param(IS_TIM_OCN_POLARITY(TIM_OCInitStruct->TIM_OCNPolarity));
+ assert_param(IS_TIM_OCNIDLE_STATE(TIM_OCInitStruct->TIM_OCNIdleState));
+ assert_param(IS_TIM_OCIDLE_STATE(TIM_OCInitStruct->TIM_OCIdleState));
+
+ /* Reset the Output N Polarity level */
+ tmpccer &= (uint16_t)(~((uint16_t)TIM_CCER_CC3NP));
+ /* Set the Output N Polarity */
+ tmpccer |= (uint16_t)(TIM_OCInitStruct->TIM_OCNPolarity << 8);
+ /* Reset the Output N State */
+ tmpccer &= (uint16_t)(~((uint16_t)TIM_CCER_CC3NE));
+
+ /* Set the Output N State */
+ tmpccer |= (uint16_t)(TIM_OCInitStruct->TIM_OutputNState << 8);
+ /* Reset the Output Compare and Output Compare N IDLE State */
+ tmpcr2 &= (uint16_t)(~((uint16_t)TIM_CR2_OIS3));
+ tmpcr2 &= (uint16_t)(~((uint16_t)TIM_CR2_OIS3N));
+ /* Set the Output Idle state */
+ tmpcr2 |= (uint16_t)(TIM_OCInitStruct->TIM_OCIdleState << 4);
+ /* Set the Output N Idle state */
+ tmpcr2 |= (uint16_t)(TIM_OCInitStruct->TIM_OCNIdleState << 4);
+ }
+ /* Write to TIMx CR2 */
+ TIMx->CR2 = tmpcr2;
+
+ /* Write to TIMx CCMR2 */
+ TIMx->CCMR2 = tmpccmrx;
+
+ /* Set the Capture Compare Register value */
+ TIMx->CCR3 = TIM_OCInitStruct->TIM_Pulse;
+
+ /* Write to TIMx CCER */
+ TIMx->CCER = tmpccer;
+}
+
+/**
+ * @brief Initializes the TIMx Channel4 according to the specified
+ * parameters in the TIM_OCInitStruct.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_OCInitStruct: pointer to a TIM_OCInitTypeDef structure
+ * that contains the configuration information for the specified TIM peripheral.
+ * @retval None
+ */
+void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)
+{
+ uint16_t tmpccmrx = 0, tmpccer = 0, tmpcr2 = 0;
+
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_OC_MODE(TIM_OCInitStruct->TIM_OCMode));
+ assert_param(IS_TIM_OUTPUT_STATE(TIM_OCInitStruct->TIM_OutputState));
+ assert_param(IS_TIM_OC_POLARITY(TIM_OCInitStruct->TIM_OCPolarity));
+ /* Disable the Channel 2: Reset the CC4E Bit */
+ TIMx->CCER &= (uint16_t)(~((uint16_t)TIM_CCER_CC4E));
+
+ /* Get the TIMx CCER register value */
+ tmpccer = TIMx->CCER;
+ /* Get the TIMx CR2 register value */
+ tmpcr2 = TIMx->CR2;
+
+ /* Get the TIMx CCMR2 register value */
+ tmpccmrx = TIMx->CCMR2;
+
+ /* Reset the Output Compare mode and Capture/Compare selection Bits */
+ tmpccmrx &= (uint16_t)(~((uint16_t)TIM_CCMR2_OC4M));
+ tmpccmrx &= (uint16_t)(~((uint16_t)TIM_CCMR2_CC4S));
+
+ /* Select the Output Compare Mode */
+ tmpccmrx |= (uint16_t)(TIM_OCInitStruct->TIM_OCMode << 8);
+
+ /* Reset the Output Polarity level */
+ tmpccer &= (uint16_t)(~((uint16_t)TIM_CCER_CC4P));
+ /* Set the Output Compare Polarity */
+ tmpccer |= (uint16_t)(TIM_OCInitStruct->TIM_OCPolarity << 12);
+
+ /* Set the Output State */
+ tmpccer |= (uint16_t)(TIM_OCInitStruct->TIM_OutputState << 12);
+
+ if((TIMx == TIM1) || (TIMx == TIM8))
+ {
+ assert_param(IS_TIM_OCIDLE_STATE(TIM_OCInitStruct->TIM_OCIdleState));
+ /* Reset the Output Compare IDLE State */
+ tmpcr2 &= (uint16_t)(~((uint16_t)TIM_CR2_OIS4));
+ /* Set the Output Idle state */
+ tmpcr2 |= (uint16_t)(TIM_OCInitStruct->TIM_OCIdleState << 6);
+ }
+ /* Write to TIMx CR2 */
+ TIMx->CR2 = tmpcr2;
+
+ /* Write to TIMx CCMR2 */
+ TIMx->CCMR2 = tmpccmrx;
+
+ /* Set the Capture Compare Register value */
+ TIMx->CCR4 = TIM_OCInitStruct->TIM_Pulse;
+
+ /* Write to TIMx CCER */
+ TIMx->CCER = tmpccer;
+}
+
+/**
+ * @brief Initializes the TIM peripheral according to the specified
+ * parameters in the TIM_ICInitStruct.
+ * @param TIMx: where x can be 1 to 17 except 6 and 7 to select the TIM peripheral.
+ * @param TIM_ICInitStruct: pointer to a TIM_ICInitTypeDef structure
+ * that contains the configuration information for the specified TIM peripheral.
+ * @retval None
+ */
+void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_CHANNEL(TIM_ICInitStruct->TIM_Channel));
+ assert_param(IS_TIM_IC_SELECTION(TIM_ICInitStruct->TIM_ICSelection));
+ assert_param(IS_TIM_IC_PRESCALER(TIM_ICInitStruct->TIM_ICPrescaler));
+ assert_param(IS_TIM_IC_FILTER(TIM_ICInitStruct->TIM_ICFilter));
+
+ if((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM2) || (TIMx == TIM3) ||
+ (TIMx == TIM4) ||(TIMx == TIM5))
+ {
+ assert_param(IS_TIM_IC_POLARITY(TIM_ICInitStruct->TIM_ICPolarity));
+ }
+ else
+ {
+ assert_param(IS_TIM_IC_POLARITY_LITE(TIM_ICInitStruct->TIM_ICPolarity));
+ }
+ if (TIM_ICInitStruct->TIM_Channel == TIM_Channel_1)
+ {
+ assert_param(IS_TIM_LIST8_PERIPH(TIMx));
+ /* TI1 Configuration */
+ TI1_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity,
+ TIM_ICInitStruct->TIM_ICSelection,
+ TIM_ICInitStruct->TIM_ICFilter);
+ /* Set the Input Capture Prescaler value */
+ TIM_SetIC1Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);
+ }
+ else if (TIM_ICInitStruct->TIM_Channel == TIM_Channel_2)
+ {
+ assert_param(IS_TIM_LIST6_PERIPH(TIMx));
+ /* TI2 Configuration */
+ TI2_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity,
+ TIM_ICInitStruct->TIM_ICSelection,
+ TIM_ICInitStruct->TIM_ICFilter);
+ /* Set the Input Capture Prescaler value */
+ TIM_SetIC2Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);
+ }
+ else if (TIM_ICInitStruct->TIM_Channel == TIM_Channel_3)
+ {
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ /* TI3 Configuration */
+ TI3_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity,
+ TIM_ICInitStruct->TIM_ICSelection,
+ TIM_ICInitStruct->TIM_ICFilter);
+ /* Set the Input Capture Prescaler value */
+ TIM_SetIC3Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);
+ }
+ else
+ {
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ /* TI4 Configuration */
+ TI4_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity,
+ TIM_ICInitStruct->TIM_ICSelection,
+ TIM_ICInitStruct->TIM_ICFilter);
+ /* Set the Input Capture Prescaler value */
+ TIM_SetIC4Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);
+ }
+}
+
+/**
+ * @brief Configures the TIM peripheral according to the specified
+ * parameters in the TIM_ICInitStruct to measure an external PWM signal.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 9, 12 or 15 to select the TIM peripheral.
+ * @param TIM_ICInitStruct: pointer to a TIM_ICInitTypeDef structure
+ * that contains the configuration information for the specified TIM peripheral.
+ * @retval None
+ */
+void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct)
+{
+ uint16_t icoppositepolarity = TIM_ICPolarity_Rising;
+ uint16_t icoppositeselection = TIM_ICSelection_DirectTI;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST6_PERIPH(TIMx));
+ /* Select the Opposite Input Polarity */
+ if (TIM_ICInitStruct->TIM_ICPolarity == TIM_ICPolarity_Rising)
+ {
+ icoppositepolarity = TIM_ICPolarity_Falling;
+ }
+ else
+ {
+ icoppositepolarity = TIM_ICPolarity_Rising;
+ }
+ /* Select the Opposite Input */
+ if (TIM_ICInitStruct->TIM_ICSelection == TIM_ICSelection_DirectTI)
+ {
+ icoppositeselection = TIM_ICSelection_IndirectTI;
+ }
+ else
+ {
+ icoppositeselection = TIM_ICSelection_DirectTI;
+ }
+ if (TIM_ICInitStruct->TIM_Channel == TIM_Channel_1)
+ {
+ /* TI1 Configuration */
+ TI1_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity, TIM_ICInitStruct->TIM_ICSelection,
+ TIM_ICInitStruct->TIM_ICFilter);
+ /* Set the Input Capture Prescaler value */
+ TIM_SetIC1Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);
+ /* TI2 Configuration */
+ TI2_Config(TIMx, icoppositepolarity, icoppositeselection, TIM_ICInitStruct->TIM_ICFilter);
+ /* Set the Input Capture Prescaler value */
+ TIM_SetIC2Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);
+ }
+ else
+ {
+ /* TI2 Configuration */
+ TI2_Config(TIMx, TIM_ICInitStruct->TIM_ICPolarity, TIM_ICInitStruct->TIM_ICSelection,
+ TIM_ICInitStruct->TIM_ICFilter);
+ /* Set the Input Capture Prescaler value */
+ TIM_SetIC2Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);
+ /* TI1 Configuration */
+ TI1_Config(TIMx, icoppositepolarity, icoppositeselection, TIM_ICInitStruct->TIM_ICFilter);
+ /* Set the Input Capture Prescaler value */
+ TIM_SetIC1Prescaler(TIMx, TIM_ICInitStruct->TIM_ICPrescaler);
+ }
+}
+
+/**
+ * @brief Configures the: Break feature, dead time, Lock level, the OSSI,
+ * the OSSR State and the AOE(automatic output enable).
+ * @param TIMx: where x can be 1 or 8 to select the TIM
+ * @param TIM_BDTRInitStruct: pointer to a TIM_BDTRInitTypeDef structure that
+ * contains the BDTR Register configuration information for the TIM peripheral.
+ * @retval None
+ */
+void TIM_BDTRConfig(TIM_TypeDef* TIMx, TIM_BDTRInitTypeDef *TIM_BDTRInitStruct)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST2_PERIPH(TIMx));
+ assert_param(IS_TIM_OSSR_STATE(TIM_BDTRInitStruct->TIM_OSSRState));
+ assert_param(IS_TIM_OSSI_STATE(TIM_BDTRInitStruct->TIM_OSSIState));
+ assert_param(IS_TIM_LOCK_LEVEL(TIM_BDTRInitStruct->TIM_LOCKLevel));
+ assert_param(IS_TIM_BREAK_STATE(TIM_BDTRInitStruct->TIM_Break));
+ assert_param(IS_TIM_BREAK_POLARITY(TIM_BDTRInitStruct->TIM_BreakPolarity));
+ assert_param(IS_TIM_AUTOMATIC_OUTPUT_STATE(TIM_BDTRInitStruct->TIM_AutomaticOutput));
+ /* Set the Lock level, the Break enable Bit and the Ploarity, the OSSR State,
+ the OSSI State, the dead time value and the Automatic Output Enable Bit */
+ TIMx->BDTR = (uint32_t)TIM_BDTRInitStruct->TIM_OSSRState | TIM_BDTRInitStruct->TIM_OSSIState |
+ TIM_BDTRInitStruct->TIM_LOCKLevel | TIM_BDTRInitStruct->TIM_DeadTime |
+ TIM_BDTRInitStruct->TIM_Break | TIM_BDTRInitStruct->TIM_BreakPolarity |
+ TIM_BDTRInitStruct->TIM_AutomaticOutput;
+}
+
+/**
+ * @brief Fills each TIM_TimeBaseInitStruct member with its default value.
+ * @param TIM_TimeBaseInitStruct : pointer to a TIM_TimeBaseInitTypeDef
+ * structure which will be initialized.
+ * @retval None
+ */
+void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
+{
+ /* Set the default configuration */
+ TIM_TimeBaseInitStruct->TIM_Period = 0xFFFF;
+ TIM_TimeBaseInitStruct->TIM_Prescaler = 0x0000;
+ TIM_TimeBaseInitStruct->TIM_ClockDivision = TIM_CKD_DIV1;
+ TIM_TimeBaseInitStruct->TIM_CounterMode = TIM_CounterMode_Up;
+ TIM_TimeBaseInitStruct->TIM_RepetitionCounter = 0x0000;
+}
+
+/**
+ * @brief Fills each TIM_OCInitStruct member with its default value.
+ * @param TIM_OCInitStruct : pointer to a TIM_OCInitTypeDef structure which will
+ * be initialized.
+ * @retval None
+ */
+void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct)
+{
+ /* Set the default configuration */
+ TIM_OCInitStruct->TIM_OCMode = TIM_OCMode_Timing;
+ TIM_OCInitStruct->TIM_OutputState = TIM_OutputState_Disable;
+ TIM_OCInitStruct->TIM_OutputNState = TIM_OutputNState_Disable;
+ TIM_OCInitStruct->TIM_Pulse = 0x0000;
+ TIM_OCInitStruct->TIM_OCPolarity = TIM_OCPolarity_High;
+ TIM_OCInitStruct->TIM_OCNPolarity = TIM_OCPolarity_High;
+ TIM_OCInitStruct->TIM_OCIdleState = TIM_OCIdleState_Reset;
+ TIM_OCInitStruct->TIM_OCNIdleState = TIM_OCNIdleState_Reset;
+}
+
+/**
+ * @brief Fills each TIM_ICInitStruct member with its default value.
+ * @param TIM_ICInitStruct: pointer to a TIM_ICInitTypeDef structure which will
+ * be initialized.
+ * @retval None
+ */
+void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct)
+{
+ /* Set the default configuration */
+ TIM_ICInitStruct->TIM_Channel = TIM_Channel_1;
+ TIM_ICInitStruct->TIM_ICPolarity = TIM_ICPolarity_Rising;
+ TIM_ICInitStruct->TIM_ICSelection = TIM_ICSelection_DirectTI;
+ TIM_ICInitStruct->TIM_ICPrescaler = TIM_ICPSC_DIV1;
+ TIM_ICInitStruct->TIM_ICFilter = 0x00;
+}
+
+/**
+ * @brief Fills each TIM_BDTRInitStruct member with its default value.
+ * @param TIM_BDTRInitStruct: pointer to a TIM_BDTRInitTypeDef structure which
+ * will be initialized.
+ * @retval None
+ */
+void TIM_BDTRStructInit(TIM_BDTRInitTypeDef* TIM_BDTRInitStruct)
+{
+ /* Set the default configuration */
+ TIM_BDTRInitStruct->TIM_OSSRState = TIM_OSSRState_Disable;
+ TIM_BDTRInitStruct->TIM_OSSIState = TIM_OSSIState_Disable;
+ TIM_BDTRInitStruct->TIM_LOCKLevel = TIM_LOCKLevel_OFF;
+ TIM_BDTRInitStruct->TIM_DeadTime = 0x00;
+ TIM_BDTRInitStruct->TIM_Break = TIM_Break_Disable;
+ TIM_BDTRInitStruct->TIM_BreakPolarity = TIM_BreakPolarity_Low;
+ TIM_BDTRInitStruct->TIM_AutomaticOutput = TIM_AutomaticOutput_Disable;
+}
+
+/**
+ * @brief Enables or disables the specified TIM peripheral.
+ * @param TIMx: where x can be 1 to 17 to select the TIMx peripheral.
+ * @param NewState: new state of the TIMx peripheral.
+ * This parameter can be: ENABLE or DISABLE.
+ * @retval None
+ */
+void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+ assert_param(IS_FUNCTIONAL_STATE(NewState));
+
+ if (NewState != DISABLE)
+ {
+ /* Enable the TIM Counter */
+ TIMx->CR1 |= TIM_CR1_CEN;
+ }
+ else
+ {
+ /* Disable the TIM Counter */
+ TIMx->CR1 &= (uint16_t)(~((uint16_t)TIM_CR1_CEN));
+ }
+}
+
+/**
+ * @brief Enables or disables the TIM peripheral Main Outputs.
+ * @param TIMx: where x can be 1, 8, 15, 16 or 17 to select the TIMx peripheral.
+ * @param NewState: new state of the TIM peripheral Main Outputs.
+ * This parameter can be: ENABLE or DISABLE.
+ * @retval None
+ */
+void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST2_PERIPH(TIMx));
+ assert_param(IS_FUNCTIONAL_STATE(NewState));
+ if (NewState != DISABLE)
+ {
+ /* Enable the TIM Main Output */
+ TIMx->BDTR |= TIM_BDTR_MOE;
+ }
+ else
+ {
+ /* Disable the TIM Main Output */
+ TIMx->BDTR &= (uint16_t)(~((uint16_t)TIM_BDTR_MOE));
+ }
+}
+
+/**
+ * @brief Enables or disables the specified TIM interrupts.
+ * @param TIMx: where x can be 1 to 17 to select the TIMx peripheral.
+ * @param TIM_IT: specifies the TIM interrupts sources to be enabled or disabled.
+ * This parameter can be any combination of the following values:
+ * @arg TIM_IT_Update: TIM update Interrupt source
+ * @arg TIM_IT_CC1: TIM Capture Compare 1 Interrupt source
+ * @arg TIM_IT_CC2: TIM Capture Compare 2 Interrupt source
+ * @arg TIM_IT_CC3: TIM Capture Compare 3 Interrupt source
+ * @arg TIM_IT_CC4: TIM Capture Compare 4 Interrupt source
+ * @arg TIM_IT_COM: TIM Commutation Interrupt source
+ * @arg TIM_IT_Trigger: TIM Trigger Interrupt source
+ * @arg TIM_IT_Break: TIM Break Interrupt source
+ * @note
+ * - TIM6 and TIM7 can only generate an update interrupt.
+ * - TIM9, TIM12 and TIM15 can have only TIM_IT_Update, TIM_IT_CC1,
+ * TIM_IT_CC2 or TIM_IT_Trigger.
+ * - TIM10, TIM11, TIM13, TIM14, TIM16 and TIM17 can have TIM_IT_Update or TIM_IT_CC1.
+ * - TIM_IT_Break is used only with TIM1, TIM8 and TIM15.
+ * - TIM_IT_COM is used only with TIM1, TIM8, TIM15, TIM16 and TIM17.
+ * @param NewState: new state of the TIM interrupts.
+ * This parameter can be: ENABLE or DISABLE.
+ * @retval None
+ */
+void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+ assert_param(IS_TIM_IT(TIM_IT));
+ assert_param(IS_FUNCTIONAL_STATE(NewState));
+
+ if (NewState != DISABLE)
+ {
+ /* Enable the Interrupt sources */
+ TIMx->DIER |= TIM_IT;
+ }
+ else
+ {
+ /* Disable the Interrupt sources */
+ TIMx->DIER &= (uint16_t)~TIM_IT;
+ }
+}
+
+/**
+ * @brief Configures the TIMx event to be generate by software.
+ * @param TIMx: where x can be 1 to 17 to select the TIM peripheral.
+ * @param TIM_EventSource: specifies the event source.
+ * This parameter can be one or more of the following values:
+ * @arg TIM_EventSource_Update: Timer update Event source
+ * @arg TIM_EventSource_CC1: Timer Capture Compare 1 Event source
+ * @arg TIM_EventSource_CC2: Timer Capture Compare 2 Event source
+ * @arg TIM_EventSource_CC3: Timer Capture Compare 3 Event source
+ * @arg TIM_EventSource_CC4: Timer Capture Compare 4 Event source
+ * @arg TIM_EventSource_COM: Timer COM event source
+ * @arg TIM_EventSource_Trigger: Timer Trigger Event source
+ * @arg TIM_EventSource_Break: Timer Break event source
+ * @note
+ * - TIM6 and TIM7 can only generate an update event.
+ * - TIM_EventSource_COM and TIM_EventSource_Break are used only with TIM1 and TIM8.
+ * @retval None
+ */
+void TIM_GenerateEvent(TIM_TypeDef* TIMx, uint16_t TIM_EventSource)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+ assert_param(IS_TIM_EVENT_SOURCE(TIM_EventSource));
+
+ /* Set the event sources */
+ TIMx->EGR = TIM_EventSource;
+}
+
+/**
+ * @brief Configures the TIMx's DMA interface.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 15, 16 or 17 to select
+ * the TIM peripheral.
+ * @param TIM_DMABase: DMA Base address.
+ * This parameter can be one of the following values:
+ * @arg TIM_DMABase_CR, TIM_DMABase_CR2, TIM_DMABase_SMCR,
+ * TIM_DMABase_DIER, TIM1_DMABase_SR, TIM_DMABase_EGR,
+ * TIM_DMABase_CCMR1, TIM_DMABase_CCMR2, TIM_DMABase_CCER,
+ * TIM_DMABase_CNT, TIM_DMABase_PSC, TIM_DMABase_ARR,
+ * TIM_DMABase_RCR, TIM_DMABase_CCR1, TIM_DMABase_CCR2,
+ * TIM_DMABase_CCR3, TIM_DMABase_CCR4, TIM_DMABase_BDTR,
+ * TIM_DMABase_DCR.
+ * @param TIM_DMABurstLength: DMA Burst length.
+ * This parameter can be one value between:
+ * TIM_DMABurstLength_1Transfer and TIM_DMABurstLength_18Transfers.
+ * @retval None
+ */
+void TIM_DMAConfig(TIM_TypeDef* TIMx, uint16_t TIM_DMABase, uint16_t TIM_DMABurstLength)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST4_PERIPH(TIMx));
+ assert_param(IS_TIM_DMA_BASE(TIM_DMABase));
+ assert_param(IS_TIM_DMA_LENGTH(TIM_DMABurstLength));
+ /* Set the DMA Base and the DMA Burst Length */
+ TIMx->DCR = TIM_DMABase | TIM_DMABurstLength;
+}
+
+/**
+ * @brief Enables or disables the TIMx's DMA Requests.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 6, 7, 8, 15, 16 or 17
+ * to select the TIM peripheral.
+ * @param TIM_DMASource: specifies the DMA Request sources.
+ * This parameter can be any combination of the following values:
+ * @arg TIM_DMA_Update: TIM update Interrupt source
+ * @arg TIM_DMA_CC1: TIM Capture Compare 1 DMA source
+ * @arg TIM_DMA_CC2: TIM Capture Compare 2 DMA source
+ * @arg TIM_DMA_CC3: TIM Capture Compare 3 DMA source
+ * @arg TIM_DMA_CC4: TIM Capture Compare 4 DMA source
+ * @arg TIM_DMA_COM: TIM Commutation DMA source
+ * @arg TIM_DMA_Trigger: TIM Trigger DMA source
+ * @param NewState: new state of the DMA Request sources.
+ * This parameter can be: ENABLE or DISABLE.
+ * @retval None
+ */
+void TIM_DMACmd(TIM_TypeDef* TIMx, uint16_t TIM_DMASource, FunctionalState NewState)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST9_PERIPH(TIMx));
+ assert_param(IS_TIM_DMA_SOURCE(TIM_DMASource));
+ assert_param(IS_FUNCTIONAL_STATE(NewState));
+
+ if (NewState != DISABLE)
+ {
+ /* Enable the DMA sources */
+ TIMx->DIER |= TIM_DMASource;
+ }
+ else
+ {
+ /* Disable the DMA sources */
+ TIMx->DIER &= (uint16_t)~TIM_DMASource;
+ }
+}
+
+/**
+ * @brief Configures the TIMx internal Clock
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 9, 12 or 15
+ * to select the TIM peripheral.
+ * @retval None
+ */
+void TIM_InternalClockConfig(TIM_TypeDef* TIMx)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST6_PERIPH(TIMx));
+ /* Disable slave mode to clock the prescaler directly with the internal clock */
+ TIMx->SMCR &= (uint16_t)(~((uint16_t)TIM_SMCR_SMS));
+}
+
+/**
+ * @brief Configures the TIMx Internal Trigger as External Clock
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 9, 12 or 15 to select the TIM peripheral.
+ * @param TIM_ITRSource: Trigger source.
+ * This parameter can be one of the following values:
+ * @param TIM_TS_ITR0: Internal Trigger 0
+ * @param TIM_TS_ITR1: Internal Trigger 1
+ * @param TIM_TS_ITR2: Internal Trigger 2
+ * @param TIM_TS_ITR3: Internal Trigger 3
+ * @retval None
+ */
+void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST6_PERIPH(TIMx));
+ assert_param(IS_TIM_INTERNAL_TRIGGER_SELECTION(TIM_InputTriggerSource));
+ /* Select the Internal Trigger */
+ TIM_SelectInputTrigger(TIMx, TIM_InputTriggerSource);
+ /* Select the External clock mode1 */
+ TIMx->SMCR |= TIM_SlaveMode_External1;
+}
+
+/**
+ * @brief Configures the TIMx Trigger as External Clock
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 9, 12 or 15 to select the TIM peripheral.
+ * @param TIM_TIxExternalCLKSource: Trigger source.
+ * This parameter can be one of the following values:
+ * @arg TIM_TIxExternalCLK1Source_TI1ED: TI1 Edge Detector
+ * @arg TIM_TIxExternalCLK1Source_TI1: Filtered Timer Input 1
+ * @arg TIM_TIxExternalCLK1Source_TI2: Filtered Timer Input 2
+ * @param TIM_ICPolarity: specifies the TIx Polarity.
+ * This parameter can be one of the following values:
+ * @arg TIM_ICPolarity_Rising
+ * @arg TIM_ICPolarity_Falling
+ * @param ICFilter : specifies the filter value.
+ * This parameter must be a value between 0x0 and 0xF.
+ * @retval None
+ */
+void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,
+ uint16_t TIM_ICPolarity, uint16_t ICFilter)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST6_PERIPH(TIMx));
+ assert_param(IS_TIM_TIXCLK_SOURCE(TIM_TIxExternalCLKSource));
+ assert_param(IS_TIM_IC_POLARITY(TIM_ICPolarity));
+ assert_param(IS_TIM_IC_FILTER(ICFilter));
+ /* Configure the Timer Input Clock Source */
+ if (TIM_TIxExternalCLKSource == TIM_TIxExternalCLK1Source_TI2)
+ {
+ TI2_Config(TIMx, TIM_ICPolarity, TIM_ICSelection_DirectTI, ICFilter);
+ }
+ else
+ {
+ TI1_Config(TIMx, TIM_ICPolarity, TIM_ICSelection_DirectTI, ICFilter);
+ }
+ /* Select the Trigger source */
+ TIM_SelectInputTrigger(TIMx, TIM_TIxExternalCLKSource);
+ /* Select the External clock mode1 */
+ TIMx->SMCR |= TIM_SlaveMode_External1;
+}
+
+/**
+ * @brief Configures the External clock Mode1
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_ExtTRGPrescaler: The external Trigger Prescaler.
+ * This parameter can be one of the following values:
+ * @arg TIM_ExtTRGPSC_OFF: ETRP Prescaler OFF.
+ * @arg TIM_ExtTRGPSC_DIV2: ETRP frequency divided by 2.
+ * @arg TIM_ExtTRGPSC_DIV4: ETRP frequency divided by 4.
+ * @arg TIM_ExtTRGPSC_DIV8: ETRP frequency divided by 8.
+ * @param TIM_ExtTRGPolarity: The external Trigger Polarity.
+ * This parameter can be one of the following values:
+ * @arg TIM_ExtTRGPolarity_Inverted: active low or falling edge active.
+ * @arg TIM_ExtTRGPolarity_NonInverted: active high or rising edge active.
+ * @param ExtTRGFilter: External Trigger Filter.
+ * This parameter must be a value between 0x00 and 0x0F
+ * @retval None
+ */
+void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
+ uint16_t ExtTRGFilter)
+{
+ uint16_t tmpsmcr = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_EXT_PRESCALER(TIM_ExtTRGPrescaler));
+ assert_param(IS_TIM_EXT_POLARITY(TIM_ExtTRGPolarity));
+ assert_param(IS_TIM_EXT_FILTER(ExtTRGFilter));
+ /* Configure the ETR Clock source */
+ TIM_ETRConfig(TIMx, TIM_ExtTRGPrescaler, TIM_ExtTRGPolarity, ExtTRGFilter);
+
+ /* Get the TIMx SMCR register value */
+ tmpsmcr = TIMx->SMCR;
+ /* Reset the SMS Bits */
+ tmpsmcr &= (uint16_t)(~((uint16_t)TIM_SMCR_SMS));
+ /* Select the External clock mode1 */
+ tmpsmcr |= TIM_SlaveMode_External1;
+ /* Select the Trigger selection : ETRF */
+ tmpsmcr &= (uint16_t)(~((uint16_t)TIM_SMCR_TS));
+ tmpsmcr |= TIM_TS_ETRF;
+ /* Write to TIMx SMCR */
+ TIMx->SMCR = tmpsmcr;
+}
+
+/**
+ * @brief Configures the External clock Mode2
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_ExtTRGPrescaler: The external Trigger Prescaler.
+ * This parameter can be one of the following values:
+ * @arg TIM_ExtTRGPSC_OFF: ETRP Prescaler OFF.
+ * @arg TIM_ExtTRGPSC_DIV2: ETRP frequency divided by 2.
+ * @arg TIM_ExtTRGPSC_DIV4: ETRP frequency divided by 4.
+ * @arg TIM_ExtTRGPSC_DIV8: ETRP frequency divided by 8.
+ * @param TIM_ExtTRGPolarity: The external Trigger Polarity.
+ * This parameter can be one of the following values:
+ * @arg TIM_ExtTRGPolarity_Inverted: active low or falling edge active.
+ * @arg TIM_ExtTRGPolarity_NonInverted: active high or rising edge active.
+ * @param ExtTRGFilter: External Trigger Filter.
+ * This parameter must be a value between 0x00 and 0x0F
+ * @retval None
+ */
+void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler,
+ uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_EXT_PRESCALER(TIM_ExtTRGPrescaler));
+ assert_param(IS_TIM_EXT_POLARITY(TIM_ExtTRGPolarity));
+ assert_param(IS_TIM_EXT_FILTER(ExtTRGFilter));
+ /* Configure the ETR Clock source */
+ TIM_ETRConfig(TIMx, TIM_ExtTRGPrescaler, TIM_ExtTRGPolarity, ExtTRGFilter);
+ /* Enable the External clock mode2 */
+ TIMx->SMCR |= TIM_SMCR_ECE;
+}
+
+/**
+ * @brief Configures the TIMx External Trigger (ETR).
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_ExtTRGPrescaler: The external Trigger Prescaler.
+ * This parameter can be one of the following values:
+ * @arg TIM_ExtTRGPSC_OFF: ETRP Prescaler OFF.
+ * @arg TIM_ExtTRGPSC_DIV2: ETRP frequency divided by 2.
+ * @arg TIM_ExtTRGPSC_DIV4: ETRP frequency divided by 4.
+ * @arg TIM_ExtTRGPSC_DIV8: ETRP frequency divided by 8.
+ * @param TIM_ExtTRGPolarity: The external Trigger Polarity.
+ * This parameter can be one of the following values:
+ * @arg TIM_ExtTRGPolarity_Inverted: active low or falling edge active.
+ * @arg TIM_ExtTRGPolarity_NonInverted: active high or rising edge active.
+ * @param ExtTRGFilter: External Trigger Filter.
+ * This parameter must be a value between 0x00 and 0x0F
+ * @retval None
+ */
+void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
+ uint16_t ExtTRGFilter)
+{
+ uint16_t tmpsmcr = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_EXT_PRESCALER(TIM_ExtTRGPrescaler));
+ assert_param(IS_TIM_EXT_POLARITY(TIM_ExtTRGPolarity));
+ assert_param(IS_TIM_EXT_FILTER(ExtTRGFilter));
+ tmpsmcr = TIMx->SMCR;
+ /* Reset the ETR Bits */
+ tmpsmcr &= SMCR_ETR_Mask;
+ /* Set the Prescaler, the Filter value and the Polarity */
+ tmpsmcr |= (uint16_t)(TIM_ExtTRGPrescaler | (uint16_t)(TIM_ExtTRGPolarity | (uint16_t)(ExtTRGFilter << (uint16_t)8)));
+ /* Write to TIMx SMCR */
+ TIMx->SMCR = tmpsmcr;
+}
+
+/**
+ * @brief Configures the TIMx Prescaler.
+ * @param TIMx: where x can be 1 to 17 to select the TIM peripheral.
+ * @param Prescaler: specifies the Prescaler Register value
+ * @param TIM_PSCReloadMode: specifies the TIM Prescaler Reload mode
+ * This parameter can be one of the following values:
+ * @arg TIM_PSCReloadMode_Update: The Prescaler is loaded at the update event.
+ * @arg TIM_PSCReloadMode_Immediate: The Prescaler is loaded immediately.
+ * @retval None
+ */
+void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+ assert_param(IS_TIM_PRESCALER_RELOAD(TIM_PSCReloadMode));
+ /* Set the Prescaler value */
+ TIMx->PSC = Prescaler;
+ /* Set or reset the UG Bit */
+ TIMx->EGR = TIM_PSCReloadMode;
+}
+
+/**
+ * @brief Specifies the TIMx Counter Mode to be used.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_CounterMode: specifies the Counter Mode to be used
+ * This parameter can be one of the following values:
+ * @arg TIM_CounterMode_Up: TIM Up Counting Mode
+ * @arg TIM_CounterMode_Down: TIM Down Counting Mode
+ * @arg TIM_CounterMode_CenterAligned1: TIM Center Aligned Mode1
+ * @arg TIM_CounterMode_CenterAligned2: TIM Center Aligned Mode2
+ * @arg TIM_CounterMode_CenterAligned3: TIM Center Aligned Mode3
+ * @retval None
+ */
+void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode)
+{
+ uint16_t tmpcr1 = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_COUNTER_MODE(TIM_CounterMode));
+ tmpcr1 = TIMx->CR1;
+ /* Reset the CMS and DIR Bits */
+ tmpcr1 &= (uint16_t)(~((uint16_t)(TIM_CR1_DIR | TIM_CR1_CMS)));
+ /* Set the Counter Mode */
+ tmpcr1 |= TIM_CounterMode;
+ /* Write to TIMx CR1 register */
+ TIMx->CR1 = tmpcr1;
+}
+
+/**
+ * @brief Selects the Input Trigger source
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 9, 12 or 15 to select the TIM peripheral.
+ * @param TIM_InputTriggerSource: The Input Trigger source.
+ * This parameter can be one of the following values:
+ * @arg TIM_TS_ITR0: Internal Trigger 0
+ * @arg TIM_TS_ITR1: Internal Trigger 1
+ * @arg TIM_TS_ITR2: Internal Trigger 2
+ * @arg TIM_TS_ITR3: Internal Trigger 3
+ * @arg TIM_TS_TI1F_ED: TI1 Edge Detector
+ * @arg TIM_TS_TI1FP1: Filtered Timer Input 1
+ * @arg TIM_TS_TI2FP2: Filtered Timer Input 2
+ * @arg TIM_TS_ETRF: External Trigger input
+ * @retval None
+ */
+void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource)
+{
+ uint16_t tmpsmcr = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST6_PERIPH(TIMx));
+ assert_param(IS_TIM_TRIGGER_SELECTION(TIM_InputTriggerSource));
+ /* Get the TIMx SMCR register value */
+ tmpsmcr = TIMx->SMCR;
+ /* Reset the TS Bits */
+ tmpsmcr &= (uint16_t)(~((uint16_t)TIM_SMCR_TS));
+ /* Set the Input Trigger source */
+ tmpsmcr |= TIM_InputTriggerSource;
+ /* Write to TIMx SMCR */
+ TIMx->SMCR = tmpsmcr;
+}
+
+/**
+ * @brief Configures the TIMx Encoder Interface.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_EncoderMode: specifies the TIMx Encoder Mode.
+ * This parameter can be one of the following values:
+ * @arg TIM_EncoderMode_TI1: Counter counts on TI1FP1 edge depending on TI2FP2 level.
+ * @arg TIM_EncoderMode_TI2: Counter counts on TI2FP2 edge depending on TI1FP1 level.
+ * @arg TIM_EncoderMode_TI12: Counter counts on both TI1FP1 and TI2FP2 edges depending
+ * on the level of the other input.
+ * @param TIM_IC1Polarity: specifies the IC1 Polarity
+ * This parameter can be one of the following values:
+ * @arg TIM_ICPolarity_Falling: IC Falling edge.
+ * @arg TIM_ICPolarity_Rising: IC Rising edge.
+ * @param TIM_IC2Polarity: specifies the IC2 Polarity
+ * This parameter can be one of the following values:
+ * @arg TIM_ICPolarity_Falling: IC Falling edge.
+ * @arg TIM_ICPolarity_Rising: IC Rising edge.
+ * @retval None
+ */
+void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode,
+ uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity)
+{
+ uint16_t tmpsmcr = 0;
+ uint16_t tmpccmr1 = 0;
+ uint16_t tmpccer = 0;
+
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST5_PERIPH(TIMx));
+ assert_param(IS_TIM_ENCODER_MODE(TIM_EncoderMode));
+ assert_param(IS_TIM_IC_POLARITY(TIM_IC1Polarity));
+ assert_param(IS_TIM_IC_POLARITY(TIM_IC2Polarity));
+
+ /* Get the TIMx SMCR register value */
+ tmpsmcr = TIMx->SMCR;
+
+ /* Get the TIMx CCMR1 register value */
+ tmpccmr1 = TIMx->CCMR1;
+
+ /* Get the TIMx CCER register value */
+ tmpccer = TIMx->CCER;
+
+ /* Set the encoder Mode */
+ tmpsmcr &= (uint16_t)(~((uint16_t)TIM_SMCR_SMS));
+ tmpsmcr |= TIM_EncoderMode;
+
+ /* Select the Capture Compare 1 and the Capture Compare 2 as input */
+ tmpccmr1 &= (uint16_t)(((uint16_t)~((uint16_t)TIM_CCMR1_CC1S)) & (uint16_t)(~((uint16_t)TIM_CCMR1_CC2S)));
+ tmpccmr1 |= TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0;
+
+ /* Set the TI1 and the TI2 Polarities */
+ tmpccer &= (uint16_t)(((uint16_t)~((uint16_t)TIM_CCER_CC1P)) & ((uint16_t)~((uint16_t)TIM_CCER_CC2P)));
+ tmpccer |= (uint16_t)(TIM_IC1Polarity | (uint16_t)(TIM_IC2Polarity << (uint16_t)4));
+
+ /* Write to TIMx SMCR */
+ TIMx->SMCR = tmpsmcr;
+ /* Write to TIMx CCMR1 */
+ TIMx->CCMR1 = tmpccmr1;
+ /* Write to TIMx CCER */
+ TIMx->CCER = tmpccer;
+}
+
+/**
+ * @brief Forces the TIMx output 1 waveform to active or inactive level.
+ * @param TIMx: where x can be 1 to 17 except 6 and 7 to select the TIM peripheral.
+ * @param TIM_ForcedAction: specifies the forced Action to be set to the output waveform.
+ * This parameter can be one of the following values:
+ * @arg TIM_ForcedAction_Active: Force active level on OC1REF
+ * @arg TIM_ForcedAction_InActive: Force inactive level on OC1REF.
+ * @retval None
+ */
+void TIM_ForcedOC1Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction)
+{
+ uint16_t tmpccmr1 = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST8_PERIPH(TIMx));
+ assert_param(IS_TIM_FORCED_ACTION(TIM_ForcedAction));
+ tmpccmr1 = TIMx->CCMR1;
+ /* Reset the OC1M Bits */
+ tmpccmr1 &= (uint16_t)~((uint16_t)TIM_CCMR1_OC1M);
+ /* Configure The Forced output Mode */
+ tmpccmr1 |= TIM_ForcedAction;
+ /* Write to TIMx CCMR1 register */
+ TIMx->CCMR1 = tmpccmr1;
+}
+
+/**
+ * @brief Forces the TIMx output 2 waveform to active or inactive level.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 9, 12 or 15 to select the TIM peripheral.
+ * @param TIM_ForcedAction: specifies the forced Action to be set to the output waveform.
+ * This parameter can be one of the following values:
+ * @arg TIM_ForcedAction_Active: Force active level on OC2REF
+ * @arg TIM_ForcedAction_InActive: Force inactive level on OC2REF.
+ * @retval None
+ */
+void TIM_ForcedOC2Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction)
+{
+ uint16_t tmpccmr1 = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST6_PERIPH(TIMx));
+ assert_param(IS_TIM_FORCED_ACTION(TIM_ForcedAction));
+ tmpccmr1 = TIMx->CCMR1;
+ /* Reset the OC2M Bits */
+ tmpccmr1 &= (uint16_t)~((uint16_t)TIM_CCMR1_OC2M);
+ /* Configure The Forced output Mode */
+ tmpccmr1 |= (uint16_t)(TIM_ForcedAction << 8);
+ /* Write to TIMx CCMR1 register */
+ TIMx->CCMR1 = tmpccmr1;
+}
+
+/**
+ * @brief Forces the TIMx output 3 waveform to active or inactive level.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_ForcedAction: specifies the forced Action to be set to the output waveform.
+ * This parameter can be one of the following values:
+ * @arg TIM_ForcedAction_Active: Force active level on OC3REF
+ * @arg TIM_ForcedAction_InActive: Force inactive level on OC3REF.
+ * @retval None
+ */
+void TIM_ForcedOC3Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction)
+{
+ uint16_t tmpccmr2 = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_FORCED_ACTION(TIM_ForcedAction));
+ tmpccmr2 = TIMx->CCMR2;
+ /* Reset the OC1M Bits */
+ tmpccmr2 &= (uint16_t)~((uint16_t)TIM_CCMR2_OC3M);
+ /* Configure The Forced output Mode */
+ tmpccmr2 |= TIM_ForcedAction;
+ /* Write to TIMx CCMR2 register */
+ TIMx->CCMR2 = tmpccmr2;
+}
+
+/**
+ * @brief Forces the TIMx output 4 waveform to active or inactive level.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_ForcedAction: specifies the forced Action to be set to the output waveform.
+ * This parameter can be one of the following values:
+ * @arg TIM_ForcedAction_Active: Force active level on OC4REF
+ * @arg TIM_ForcedAction_InActive: Force inactive level on OC4REF.
+ * @retval None
+ */
+void TIM_ForcedOC4Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction)
+{
+ uint16_t tmpccmr2 = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_FORCED_ACTION(TIM_ForcedAction));
+ tmpccmr2 = TIMx->CCMR2;
+ /* Reset the OC2M Bits */
+ tmpccmr2 &= (uint16_t)~((uint16_t)TIM_CCMR2_OC4M);
+ /* Configure The Forced output Mode */
+ tmpccmr2 |= (uint16_t)(TIM_ForcedAction << 8);
+ /* Write to TIMx CCMR2 register */
+ TIMx->CCMR2 = tmpccmr2;
+}
+
+/**
+ * @brief Enables or disables TIMx peripheral Preload register on ARR.
+ * @param TIMx: where x can be 1 to 17 to select the TIM peripheral.
+ * @param NewState: new state of the TIMx peripheral Preload register
+ * This parameter can be: ENABLE or DISABLE.
+ * @retval None
+ */
+void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+ assert_param(IS_FUNCTIONAL_STATE(NewState));
+ if (NewState != DISABLE)
+ {
+ /* Set the ARR Preload Bit */
+ TIMx->CR1 |= TIM_CR1_ARPE;
+ }
+ else
+ {
+ /* Reset the ARR Preload Bit */
+ TIMx->CR1 &= (uint16_t)~((uint16_t)TIM_CR1_ARPE);
+ }
+}
+
+/**
+ * @brief Selects the TIM peripheral Commutation event.
+ * @param TIMx: where x can be 1, 8, 15, 16 or 17 to select the TIMx peripheral
+ * @param NewState: new state of the Commutation event.
+ * This parameter can be: ENABLE or DISABLE.
+ * @retval None
+ */
+void TIM_SelectCOM(TIM_TypeDef* TIMx, FunctionalState NewState)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST2_PERIPH(TIMx));
+ assert_param(IS_FUNCTIONAL_STATE(NewState));
+ if (NewState != DISABLE)
+ {
+ /* Set the COM Bit */
+ TIMx->CR2 |= TIM_CR2_CCUS;
+ }
+ else
+ {
+ /* Reset the COM Bit */
+ TIMx->CR2 &= (uint16_t)~((uint16_t)TIM_CR2_CCUS);
+ }
+}
+
+/**
+ * @brief Selects the TIMx peripheral Capture Compare DMA source.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 15, 16 or 17 to select
+ * the TIM peripheral.
+ * @param NewState: new state of the Capture Compare DMA source
+ * This parameter can be: ENABLE or DISABLE.
+ * @retval None
+ */
+void TIM_SelectCCDMA(TIM_TypeDef* TIMx, FunctionalState NewState)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST4_PERIPH(TIMx));
+ assert_param(IS_FUNCTIONAL_STATE(NewState));
+ if (NewState != DISABLE)
+ {
+ /* Set the CCDS Bit */
+ TIMx->CR2 |= TIM_CR2_CCDS;
+ }
+ else
+ {
+ /* Reset the CCDS Bit */
+ TIMx->CR2 &= (uint16_t)~((uint16_t)TIM_CR2_CCDS);
+ }
+}
+
+/**
+ * @brief Sets or Resets the TIM peripheral Capture Compare Preload Control bit.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 8 or 15
+ * to select the TIMx peripheral
+ * @param NewState: new state of the Capture Compare Preload Control bit
+ * This parameter can be: ENABLE or DISABLE.
+ * @retval None
+ */
+void TIM_CCPreloadControl(TIM_TypeDef* TIMx, FunctionalState NewState)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST5_PERIPH(TIMx));
+ assert_param(IS_FUNCTIONAL_STATE(NewState));
+ if (NewState != DISABLE)
+ {
+ /* Set the CCPC Bit */
+ TIMx->CR2 |= TIM_CR2_CCPC;
+ }
+ else
+ {
+ /* Reset the CCPC Bit */
+ TIMx->CR2 &= (uint16_t)~((uint16_t)TIM_CR2_CCPC);
+ }
+}
+
+/**
+ * @brief Enables or disables the TIMx peripheral Preload register on CCR1.
+ * @param TIMx: where x can be 1 to 17 except 6 and 7 to select the TIM peripheral.
+ * @param TIM_OCPreload: new state of the TIMx peripheral Preload register
+ * This parameter can be one of the following values:
+ * @arg TIM_OCPreload_Enable
+ * @arg TIM_OCPreload_Disable
+ * @retval None
+ */
+void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload)
+{
+ uint16_t tmpccmr1 = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST8_PERIPH(TIMx));
+ assert_param(IS_TIM_OCPRELOAD_STATE(TIM_OCPreload));
+ tmpccmr1 = TIMx->CCMR1;
+ /* Reset the OC1PE Bit */
+ tmpccmr1 &= (uint16_t)~((uint16_t)TIM_CCMR1_OC1PE);
+ /* Enable or Disable the Output Compare Preload feature */
+ tmpccmr1 |= TIM_OCPreload;
+ /* Write to TIMx CCMR1 register */
+ TIMx->CCMR1 = tmpccmr1;
+}
+
+/**
+ * @brief Enables or disables the TIMx peripheral Preload register on CCR2.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 9, 12 or 15 to select
+ * the TIM peripheral.
+ * @param TIM_OCPreload: new state of the TIMx peripheral Preload register
+ * This parameter can be one of the following values:
+ * @arg TIM_OCPreload_Enable
+ * @arg TIM_OCPreload_Disable
+ * @retval None
+ */
+void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload)
+{
+ uint16_t tmpccmr1 = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST6_PERIPH(TIMx));
+ assert_param(IS_TIM_OCPRELOAD_STATE(TIM_OCPreload));
+ tmpccmr1 = TIMx->CCMR1;
+ /* Reset the OC2PE Bit */
+ tmpccmr1 &= (uint16_t)~((uint16_t)TIM_CCMR1_OC2PE);
+ /* Enable or Disable the Output Compare Preload feature */
+ tmpccmr1 |= (uint16_t)(TIM_OCPreload << 8);
+ /* Write to TIMx CCMR1 register */
+ TIMx->CCMR1 = tmpccmr1;
+}
+
+/**
+ * @brief Enables or disables the TIMx peripheral Preload register on CCR3.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_OCPreload: new state of the TIMx peripheral Preload register
+ * This parameter can be one of the following values:
+ * @arg TIM_OCPreload_Enable
+ * @arg TIM_OCPreload_Disable
+ * @retval None
+ */
+void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload)
+{
+ uint16_t tmpccmr2 = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_OCPRELOAD_STATE(TIM_OCPreload));
+ tmpccmr2 = TIMx->CCMR2;
+ /* Reset the OC3PE Bit */
+ tmpccmr2 &= (uint16_t)~((uint16_t)TIM_CCMR2_OC3PE);
+ /* Enable or Disable the Output Compare Preload feature */
+ tmpccmr2 |= TIM_OCPreload;
+ /* Write to TIMx CCMR2 register */
+ TIMx->CCMR2 = tmpccmr2;
+}
+
+/**
+ * @brief Enables or disables the TIMx peripheral Preload register on CCR4.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_OCPreload: new state of the TIMx peripheral Preload register
+ * This parameter can be one of the following values:
+ * @arg TIM_OCPreload_Enable
+ * @arg TIM_OCPreload_Disable
+ * @retval None
+ */
+void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload)
+{
+ uint16_t tmpccmr2 = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_OCPRELOAD_STATE(TIM_OCPreload));
+ tmpccmr2 = TIMx->CCMR2;
+ /* Reset the OC4PE Bit */
+ tmpccmr2 &= (uint16_t)~((uint16_t)TIM_CCMR2_OC4PE);
+ /* Enable or Disable the Output Compare Preload feature */
+ tmpccmr2 |= (uint16_t)(TIM_OCPreload << 8);
+ /* Write to TIMx CCMR2 register */
+ TIMx->CCMR2 = tmpccmr2;
+}
+
+/**
+ * @brief Configures the TIMx Output Compare 1 Fast feature.
+ * @param TIMx: where x can be 1 to 17 except 6 and 7 to select the TIM peripheral.
+ * @param TIM_OCFast: new state of the Output Compare Fast Enable Bit.
+ * This parameter can be one of the following values:
+ * @arg TIM_OCFast_Enable: TIM output compare fast enable
+ * @arg TIM_OCFast_Disable: TIM output compare fast disable
+ * @retval None
+ */
+void TIM_OC1FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast)
+{
+ uint16_t tmpccmr1 = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST8_PERIPH(TIMx));
+ assert_param(IS_TIM_OCFAST_STATE(TIM_OCFast));
+ /* Get the TIMx CCMR1 register value */
+ tmpccmr1 = TIMx->CCMR1;
+ /* Reset the OC1FE Bit */
+ tmpccmr1 &= (uint16_t)~((uint16_t)TIM_CCMR1_OC1FE);
+ /* Enable or Disable the Output Compare Fast Bit */
+ tmpccmr1 |= TIM_OCFast;
+ /* Write to TIMx CCMR1 */
+ TIMx->CCMR1 = tmpccmr1;
+}
+
+/**
+ * @brief Configures the TIMx Output Compare 2 Fast feature.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 9, 12 or 15 to select
+ * the TIM peripheral.
+ * @param TIM_OCFast: new state of the Output Compare Fast Enable Bit.
+ * This parameter can be one of the following values:
+ * @arg TIM_OCFast_Enable: TIM output compare fast enable
+ * @arg TIM_OCFast_Disable: TIM output compare fast disable
+ * @retval None
+ */
+void TIM_OC2FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast)
+{
+ uint16_t tmpccmr1 = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST6_PERIPH(TIMx));
+ assert_param(IS_TIM_OCFAST_STATE(TIM_OCFast));
+ /* Get the TIMx CCMR1 register value */
+ tmpccmr1 = TIMx->CCMR1;
+ /* Reset the OC2FE Bit */
+ tmpccmr1 &= (uint16_t)~((uint16_t)TIM_CCMR1_OC2FE);
+ /* Enable or Disable the Output Compare Fast Bit */
+ tmpccmr1 |= (uint16_t)(TIM_OCFast << 8);
+ /* Write to TIMx CCMR1 */
+ TIMx->CCMR1 = tmpccmr1;
+}
+
+/**
+ * @brief Configures the TIMx Output Compare 3 Fast feature.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_OCFast: new state of the Output Compare Fast Enable Bit.
+ * This parameter can be one of the following values:
+ * @arg TIM_OCFast_Enable: TIM output compare fast enable
+ * @arg TIM_OCFast_Disable: TIM output compare fast disable
+ * @retval None
+ */
+void TIM_OC3FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast)
+{
+ uint16_t tmpccmr2 = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_OCFAST_STATE(TIM_OCFast));
+ /* Get the TIMx CCMR2 register value */
+ tmpccmr2 = TIMx->CCMR2;
+ /* Reset the OC3FE Bit */
+ tmpccmr2 &= (uint16_t)~((uint16_t)TIM_CCMR2_OC3FE);
+ /* Enable or Disable the Output Compare Fast Bit */
+ tmpccmr2 |= TIM_OCFast;
+ /* Write to TIMx CCMR2 */
+ TIMx->CCMR2 = tmpccmr2;
+}
+
+/**
+ * @brief Configures the TIMx Output Compare 4 Fast feature.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_OCFast: new state of the Output Compare Fast Enable Bit.
+ * This parameter can be one of the following values:
+ * @arg TIM_OCFast_Enable: TIM output compare fast enable
+ * @arg TIM_OCFast_Disable: TIM output compare fast disable
+ * @retval None
+ */
+void TIM_OC4FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast)
+{
+ uint16_t tmpccmr2 = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_OCFAST_STATE(TIM_OCFast));
+ /* Get the TIMx CCMR2 register value */
+ tmpccmr2 = TIMx->CCMR2;
+ /* Reset the OC4FE Bit */
+ tmpccmr2 &= (uint16_t)~((uint16_t)TIM_CCMR2_OC4FE);
+ /* Enable or Disable the Output Compare Fast Bit */
+ tmpccmr2 |= (uint16_t)(TIM_OCFast << 8);
+ /* Write to TIMx CCMR2 */
+ TIMx->CCMR2 = tmpccmr2;
+}
+
+/**
+ * @brief Clears or safeguards the OCREF1 signal on an external event
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_OCClear: new state of the Output Compare Clear Enable Bit.
+ * This parameter can be one of the following values:
+ * @arg TIM_OCClear_Enable: TIM Output clear enable
+ * @arg TIM_OCClear_Disable: TIM Output clear disable
+ * @retval None
+ */
+void TIM_ClearOC1Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear)
+{
+ uint16_t tmpccmr1 = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_OCCLEAR_STATE(TIM_OCClear));
+
+ tmpccmr1 = TIMx->CCMR1;
+
+ /* Reset the OC1CE Bit */
+ tmpccmr1 &= (uint16_t)~((uint16_t)TIM_CCMR1_OC1CE);
+ /* Enable or Disable the Output Compare Clear Bit */
+ tmpccmr1 |= TIM_OCClear;
+ /* Write to TIMx CCMR1 register */
+ TIMx->CCMR1 = tmpccmr1;
+}
+
+/**
+ * @brief Clears or safeguards the OCREF2 signal on an external event
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_OCClear: new state of the Output Compare Clear Enable Bit.
+ * This parameter can be one of the following values:
+ * @arg TIM_OCClear_Enable: TIM Output clear enable
+ * @arg TIM_OCClear_Disable: TIM Output clear disable
+ * @retval None
+ */
+void TIM_ClearOC2Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear)
+{
+ uint16_t tmpccmr1 = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_OCCLEAR_STATE(TIM_OCClear));
+ tmpccmr1 = TIMx->CCMR1;
+ /* Reset the OC2CE Bit */
+ tmpccmr1 &= (uint16_t)~((uint16_t)TIM_CCMR1_OC2CE);
+ /* Enable or Disable the Output Compare Clear Bit */
+ tmpccmr1 |= (uint16_t)(TIM_OCClear << 8);
+ /* Write to TIMx CCMR1 register */
+ TIMx->CCMR1 = tmpccmr1;
+}
+
+/**
+ * @brief Clears or safeguards the OCREF3 signal on an external event
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_OCClear: new state of the Output Compare Clear Enable Bit.
+ * This parameter can be one of the following values:
+ * @arg TIM_OCClear_Enable: TIM Output clear enable
+ * @arg TIM_OCClear_Disable: TIM Output clear disable
+ * @retval None
+ */
+void TIM_ClearOC3Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear)
+{
+ uint16_t tmpccmr2 = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_OCCLEAR_STATE(TIM_OCClear));
+ tmpccmr2 = TIMx->CCMR2;
+ /* Reset the OC3CE Bit */
+ tmpccmr2 &= (uint16_t)~((uint16_t)TIM_CCMR2_OC3CE);
+ /* Enable or Disable the Output Compare Clear Bit */
+ tmpccmr2 |= TIM_OCClear;
+ /* Write to TIMx CCMR2 register */
+ TIMx->CCMR2 = tmpccmr2;
+}
+
+/**
+ * @brief Clears or safeguards the OCREF4 signal on an external event
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_OCClear: new state of the Output Compare Clear Enable Bit.
+ * This parameter can be one of the following values:
+ * @arg TIM_OCClear_Enable: TIM Output clear enable
+ * @arg TIM_OCClear_Disable: TIM Output clear disable
+ * @retval None
+ */
+void TIM_ClearOC4Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear)
+{
+ uint16_t tmpccmr2 = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_OCCLEAR_STATE(TIM_OCClear));
+ tmpccmr2 = TIMx->CCMR2;
+ /* Reset the OC4CE Bit */
+ tmpccmr2 &= (uint16_t)~((uint16_t)TIM_CCMR2_OC4CE);
+ /* Enable or Disable the Output Compare Clear Bit */
+ tmpccmr2 |= (uint16_t)(TIM_OCClear << 8);
+ /* Write to TIMx CCMR2 register */
+ TIMx->CCMR2 = tmpccmr2;
+}
+
+/**
+ * @brief Configures the TIMx channel 1 polarity.
+ * @param TIMx: where x can be 1 to 17 except 6 and 7 to select the TIM peripheral.
+ * @param TIM_OCPolarity: specifies the OC1 Polarity
+ * This parameter can be one of the following values:
+ * @arg TIM_OCPolarity_High: Output Compare active high
+ * @arg TIM_OCPolarity_Low: Output Compare active low
+ * @retval None
+ */
+void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity)
+{
+ uint16_t tmpccer = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST8_PERIPH(TIMx));
+ assert_param(IS_TIM_OC_POLARITY(TIM_OCPolarity));
+ tmpccer = TIMx->CCER;
+ /* Set or Reset the CC1P Bit */
+ tmpccer &= (uint16_t)~((uint16_t)TIM_CCER_CC1P);
+ tmpccer |= TIM_OCPolarity;
+ /* Write to TIMx CCER register */
+ TIMx->CCER = tmpccer;
+}
+
+/**
+ * @brief Configures the TIMx Channel 1N polarity.
+ * @param TIMx: where x can be 1, 8, 15, 16 or 17 to select the TIM peripheral.
+ * @param TIM_OCNPolarity: specifies the OC1N Polarity
+ * This parameter can be one of the following values:
+ * @arg TIM_OCNPolarity_High: Output Compare active high
+ * @arg TIM_OCNPolarity_Low: Output Compare active low
+ * @retval None
+ */
+void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity)
+{
+ uint16_t tmpccer = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST2_PERIPH(TIMx));
+ assert_param(IS_TIM_OCN_POLARITY(TIM_OCNPolarity));
+
+ tmpccer = TIMx->CCER;
+ /* Set or Reset the CC1NP Bit */
+ tmpccer &= (uint16_t)~((uint16_t)TIM_CCER_CC1NP);
+ tmpccer |= TIM_OCNPolarity;
+ /* Write to TIMx CCER register */
+ TIMx->CCER = tmpccer;
+}
+
+/**
+ * @brief Configures the TIMx channel 2 polarity.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 9, 12 or 15 to select the TIM peripheral.
+ * @param TIM_OCPolarity: specifies the OC2 Polarity
+ * This parameter can be one of the following values:
+ * @arg TIM_OCPolarity_High: Output Compare active high
+ * @arg TIM_OCPolarity_Low: Output Compare active low
+ * @retval None
+ */
+void TIM_OC2PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity)
+{
+ uint16_t tmpccer = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST6_PERIPH(TIMx));
+ assert_param(IS_TIM_OC_POLARITY(TIM_OCPolarity));
+ tmpccer = TIMx->CCER;
+ /* Set or Reset the CC2P Bit */
+ tmpccer &= (uint16_t)~((uint16_t)TIM_CCER_CC2P);
+ tmpccer |= (uint16_t)(TIM_OCPolarity << 4);
+ /* Write to TIMx CCER register */
+ TIMx->CCER = tmpccer;
+}
+
+/**
+ * @brief Configures the TIMx Channel 2N polarity.
+ * @param TIMx: where x can be 1 or 8 to select the TIM peripheral.
+ * @param TIM_OCNPolarity: specifies the OC2N Polarity
+ * This parameter can be one of the following values:
+ * @arg TIM_OCNPolarity_High: Output Compare active high
+ * @arg TIM_OCNPolarity_Low: Output Compare active low
+ * @retval None
+ */
+void TIM_OC2NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity)
+{
+ uint16_t tmpccer = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST1_PERIPH(TIMx));
+ assert_param(IS_TIM_OCN_POLARITY(TIM_OCNPolarity));
+
+ tmpccer = TIMx->CCER;
+ /* Set or Reset the CC2NP Bit */
+ tmpccer &= (uint16_t)~((uint16_t)TIM_CCER_CC2NP);
+ tmpccer |= (uint16_t)(TIM_OCNPolarity << 4);
+ /* Write to TIMx CCER register */
+ TIMx->CCER = tmpccer;
+}
+
+/**
+ * @brief Configures the TIMx channel 3 polarity.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_OCPolarity: specifies the OC3 Polarity
+ * This parameter can be one of the following values:
+ * @arg TIM_OCPolarity_High: Output Compare active high
+ * @arg TIM_OCPolarity_Low: Output Compare active low
+ * @retval None
+ */
+void TIM_OC3PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity)
+{
+ uint16_t tmpccer = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_OC_POLARITY(TIM_OCPolarity));
+ tmpccer = TIMx->CCER;
+ /* Set or Reset the CC3P Bit */
+ tmpccer &= (uint16_t)~((uint16_t)TIM_CCER_CC3P);
+ tmpccer |= (uint16_t)(TIM_OCPolarity << 8);
+ /* Write to TIMx CCER register */
+ TIMx->CCER = tmpccer;
+}
+
+/**
+ * @brief Configures the TIMx Channel 3N polarity.
+ * @param TIMx: where x can be 1 or 8 to select the TIM peripheral.
+ * @param TIM_OCNPolarity: specifies the OC3N Polarity
+ * This parameter can be one of the following values:
+ * @arg TIM_OCNPolarity_High: Output Compare active high
+ * @arg TIM_OCNPolarity_Low: Output Compare active low
+ * @retval None
+ */
+void TIM_OC3NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity)
+{
+ uint16_t tmpccer = 0;
+
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST1_PERIPH(TIMx));
+ assert_param(IS_TIM_OCN_POLARITY(TIM_OCNPolarity));
+
+ tmpccer = TIMx->CCER;
+ /* Set or Reset the CC3NP Bit */
+ tmpccer &= (uint16_t)~((uint16_t)TIM_CCER_CC3NP);
+ tmpccer |= (uint16_t)(TIM_OCNPolarity << 8);
+ /* Write to TIMx CCER register */
+ TIMx->CCER = tmpccer;
+}
+
+/**
+ * @brief Configures the TIMx channel 4 polarity.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_OCPolarity: specifies the OC4 Polarity
+ * This parameter can be one of the following values:
+ * @arg TIM_OCPolarity_High: Output Compare active high
+ * @arg TIM_OCPolarity_Low: Output Compare active low
+ * @retval None
+ */
+void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity)
+{
+ uint16_t tmpccer = 0;
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_OC_POLARITY(TIM_OCPolarity));
+ tmpccer = TIMx->CCER;
+ /* Set or Reset the CC4P Bit */
+ tmpccer &= (uint16_t)~((uint16_t)TIM_CCER_CC4P);
+ tmpccer |= (uint16_t)(TIM_OCPolarity << 12);
+ /* Write to TIMx CCER register */
+ TIMx->CCER = tmpccer;
+}
+
+/**
+ * @brief Enables or disables the TIM Capture Compare Channel x.
+ * @param TIMx: where x can be 1 to 17 except 6 and 7 to select the TIM peripheral.
+ * @param TIM_Channel: specifies the TIM Channel
+ * This parameter can be one of the following values:
+ * @arg TIM_Channel_1: TIM Channel 1
+ * @arg TIM_Channel_2: TIM Channel 2
+ * @arg TIM_Channel_3: TIM Channel 3
+ * @arg TIM_Channel_4: TIM Channel 4
+ * @param TIM_CCx: specifies the TIM Channel CCxE bit new state.
+ * This parameter can be: TIM_CCx_Enable or TIM_CCx_Disable.
+ * @retval None
+ */
+void TIM_CCxCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCx)
+{
+ uint16_t tmp = 0;
+
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST8_PERIPH(TIMx));
+ assert_param(IS_TIM_CHANNEL(TIM_Channel));
+ assert_param(IS_TIM_CCX(TIM_CCx));
+
+ tmp = CCER_CCE_Set << TIM_Channel;
+
+ /* Reset the CCxE Bit */
+ TIMx->CCER &= (uint16_t)~ tmp;
+
+ /* Set or reset the CCxE Bit */
+ TIMx->CCER |= (uint16_t)(TIM_CCx << TIM_Channel);
+}
+
+/**
+ * @brief Enables or disables the TIM Capture Compare Channel xN.
+ * @param TIMx: where x can be 1, 8, 15, 16 or 17 to select the TIM peripheral.
+ * @param TIM_Channel: specifies the TIM Channel
+ * This parameter can be one of the following values:
+ * @arg TIM_Channel_1: TIM Channel 1
+ * @arg TIM_Channel_2: TIM Channel 2
+ * @arg TIM_Channel_3: TIM Channel 3
+ * @param TIM_CCxN: specifies the TIM Channel CCxNE bit new state.
+ * This parameter can be: TIM_CCxN_Enable or TIM_CCxN_Disable.
+ * @retval None
+ */
+void TIM_CCxNCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCxN)
+{
+ uint16_t tmp = 0;
+
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST2_PERIPH(TIMx));
+ assert_param(IS_TIM_COMPLEMENTARY_CHANNEL(TIM_Channel));
+ assert_param(IS_TIM_CCXN(TIM_CCxN));
+
+ tmp = CCER_CCNE_Set << TIM_Channel;
+
+ /* Reset the CCxNE Bit */
+ TIMx->CCER &= (uint16_t) ~tmp;
+
+ /* Set or reset the CCxNE Bit */
+ TIMx->CCER |= (uint16_t)(TIM_CCxN << TIM_Channel);
+}
+
+/**
+ * @brief Selects the TIM Output Compare Mode.
+ * @note This function disables the selected channel before changing the Output
+ * Compare Mode.
+ * User has to enable this channel using TIM_CCxCmd and TIM_CCxNCmd functions.
+ * @param TIMx: where x can be 1 to 17 except 6 and 7 to select the TIM peripheral.
+ * @param TIM_Channel: specifies the TIM Channel
+ * This parameter can be one of the following values:
+ * @arg TIM_Channel_1: TIM Channel 1
+ * @arg TIM_Channel_2: TIM Channel 2
+ * @arg TIM_Channel_3: TIM Channel 3
+ * @arg TIM_Channel_4: TIM Channel 4
+ * @param TIM_OCMode: specifies the TIM Output Compare Mode.
+ * This parameter can be one of the following values:
+ * @arg TIM_OCMode_Timing
+ * @arg TIM_OCMode_Active
+ * @arg TIM_OCMode_Toggle
+ * @arg TIM_OCMode_PWM1
+ * @arg TIM_OCMode_PWM2
+ * @arg TIM_ForcedAction_Active
+ * @arg TIM_ForcedAction_InActive
+ * @retval None
+ */
+void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode)
+{
+ uint32_t tmp = 0;
+ uint16_t tmp1 = 0;
+
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST8_PERIPH(TIMx));
+ assert_param(IS_TIM_CHANNEL(TIM_Channel));
+ assert_param(IS_TIM_OCM(TIM_OCMode));
+
+ tmp = (uint32_t) TIMx;
+ tmp += CCMR_Offset;
+
+ tmp1 = CCER_CCE_Set << (uint16_t)TIM_Channel;
+
+ /* Disable the Channel: Reset the CCxE Bit */
+ TIMx->CCER &= (uint16_t) ~tmp1;
+
+ if((TIM_Channel == TIM_Channel_1) ||(TIM_Channel == TIM_Channel_3))
+ {
+ tmp += (TIM_Channel>>1);
+
+ /* Reset the OCxM bits in the CCMRx register */
+ *(__IO uint32_t *) tmp &= (uint32_t)~((uint32_t)TIM_CCMR1_OC1M);
+
+ /* Configure the OCxM bits in the CCMRx register */
+ *(__IO uint32_t *) tmp |= TIM_OCMode;
+ }
+ else
+ {
+ tmp += (uint16_t)(TIM_Channel - (uint16_t)4)>> (uint16_t)1;
+
+ /* Reset the OCxM bits in the CCMRx register */
+ *(__IO uint32_t *) tmp &= (uint32_t)~((uint32_t)TIM_CCMR1_OC2M);
+
+ /* Configure the OCxM bits in the CCMRx register */
+ *(__IO uint32_t *) tmp |= (uint16_t)(TIM_OCMode << 8);
+ }
+}
+
+/**
+ * @brief Enables or Disables the TIMx Update event.
+ * @param TIMx: where x can be 1 to 17 to select the TIM peripheral.
+ * @param NewState: new state of the TIMx UDIS bit
+ * This parameter can be: ENABLE or DISABLE.
+ * @retval None
+ */
+void TIM_UpdateDisableConfig(TIM_TypeDef* TIMx, FunctionalState NewState)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+ assert_param(IS_FUNCTIONAL_STATE(NewState));
+ if (NewState != DISABLE)
+ {
+ /* Set the Update Disable Bit */
+ TIMx->CR1 |= TIM_CR1_UDIS;
+ }
+ else
+ {
+ /* Reset the Update Disable Bit */
+ TIMx->CR1 &= (uint16_t)~((uint16_t)TIM_CR1_UDIS);
+ }
+}
+
+/**
+ * @brief Configures the TIMx Update Request Interrupt source.
+ * @param TIMx: where x can be 1 to 17 to select the TIM peripheral.
+ * @param TIM_UpdateSource: specifies the Update source.
+ * This parameter can be one of the following values:
+ * @arg TIM_UpdateSource_Regular: Source of update is the counter overflow/underflow
+ or the setting of UG bit, or an update generation
+ through the slave mode controller.
+ * @arg TIM_UpdateSource_Global: Source of update is counter overflow/underflow.
+ * @retval None
+ */
+void TIM_UpdateRequestConfig(TIM_TypeDef* TIMx, uint16_t TIM_UpdateSource)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+ assert_param(IS_TIM_UPDATE_SOURCE(TIM_UpdateSource));
+ if (TIM_UpdateSource != TIM_UpdateSource_Global)
+ {
+ /* Set the URS Bit */
+ TIMx->CR1 |= TIM_CR1_URS;
+ }
+ else
+ {
+ /* Reset the URS Bit */
+ TIMx->CR1 &= (uint16_t)~((uint16_t)TIM_CR1_URS);
+ }
+}
+
+/**
+ * @brief Enables or disables the TIMx's Hall sensor interface.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param NewState: new state of the TIMx Hall sensor interface.
+ * This parameter can be: ENABLE or DISABLE.
+ * @retval None
+ */
+void TIM_SelectHallSensor(TIM_TypeDef* TIMx, FunctionalState NewState)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST6_PERIPH(TIMx));
+ assert_param(IS_FUNCTIONAL_STATE(NewState));
+ if (NewState != DISABLE)
+ {
+ /* Set the TI1S Bit */
+ TIMx->CR2 |= TIM_CR2_TI1S;
+ }
+ else
+ {
+ /* Reset the TI1S Bit */
+ TIMx->CR2 &= (uint16_t)~((uint16_t)TIM_CR2_TI1S);
+ }
+}
+
+/**
+ * @brief Selects the TIMx's One Pulse Mode.
+ * @param TIMx: where x can be 1 to 17 to select the TIM peripheral.
+ * @param TIM_OPMode: specifies the OPM Mode to be used.
+ * This parameter can be one of the following values:
+ * @arg TIM_OPMode_Single
+ * @arg TIM_OPMode_Repetitive
+ * @retval None
+ */
+void TIM_SelectOnePulseMode(TIM_TypeDef* TIMx, uint16_t TIM_OPMode)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+ assert_param(IS_TIM_OPM_MODE(TIM_OPMode));
+ /* Reset the OPM Bit */
+ TIMx->CR1 &= (uint16_t)~((uint16_t)TIM_CR1_OPM);
+ /* Configure the OPM Mode */
+ TIMx->CR1 |= TIM_OPMode;
+}
+
+/**
+ * @brief Selects the TIMx Trigger Output Mode.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 6, 7, 8, 9, 12 or 15 to select the TIM peripheral.
+ * @param TIM_TRGOSource: specifies the Trigger Output source.
+ * This paramter can be one of the following values:
+ *
+ * - For all TIMx
+ * @arg TIM_TRGOSource_Reset: The UG bit in the TIM_EGR register is used as the trigger output (TRGO).
+ * @arg TIM_TRGOSource_Enable: The Counter Enable CEN is used as the trigger output (TRGO).
+ * @arg TIM_TRGOSource_Update: The update event is selected as the trigger output (TRGO).
+ *
+ * - For all TIMx except TIM6 and TIM7
+ * @arg TIM_TRGOSource_OC1: The trigger output sends a positive pulse when the CC1IF flag
+ * is to be set, as soon as a capture or compare match occurs (TRGO).
+ * @arg TIM_TRGOSource_OC1Ref: OC1REF signal is used as the trigger output (TRGO).
+ * @arg TIM_TRGOSource_OC2Ref: OC2REF signal is used as the trigger output (TRGO).
+ * @arg TIM_TRGOSource_OC3Ref: OC3REF signal is used as the trigger output (TRGO).
+ * @arg TIM_TRGOSource_OC4Ref: OC4REF signal is used as the trigger output (TRGO).
+ *
+ * @retval None
+ */
+void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST7_PERIPH(TIMx));
+ assert_param(IS_TIM_TRGO_SOURCE(TIM_TRGOSource));
+ /* Reset the MMS Bits */
+ TIMx->CR2 &= (uint16_t)~((uint16_t)TIM_CR2_MMS);
+ /* Select the TRGO source */
+ TIMx->CR2 |= TIM_TRGOSource;
+}
+
+/**
+ * @brief Selects the TIMx Slave Mode.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 9, 12 or 15 to select the TIM peripheral.
+ * @param TIM_SlaveMode: specifies the Timer Slave Mode.
+ * This parameter can be one of the following values:
+ * @arg TIM_SlaveMode_Reset: Rising edge of the selected trigger signal (TRGI) re-initializes
+ * the counter and triggers an update of the registers.
+ * @arg TIM_SlaveMode_Gated: The counter clock is enabled when the trigger signal (TRGI) is high.
+ * @arg TIM_SlaveMode_Trigger: The counter starts at a rising edge of the trigger TRGI.
+ * @arg TIM_SlaveMode_External1: Rising edges of the selected trigger (TRGI) clock the counter.
+ * @retval None
+ */
+void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST6_PERIPH(TIMx));
+ assert_param(IS_TIM_SLAVE_MODE(TIM_SlaveMode));
+ /* Reset the SMS Bits */
+ TIMx->SMCR &= (uint16_t)~((uint16_t)TIM_SMCR_SMS);
+ /* Select the Slave Mode */
+ TIMx->SMCR |= TIM_SlaveMode;
+}
+
+/**
+ * @brief Sets or Resets the TIMx Master/Slave Mode.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 9, 12 or 15 to select the TIM peripheral.
+ * @param TIM_MasterSlaveMode: specifies the Timer Master Slave Mode.
+ * This parameter can be one of the following values:
+ * @arg TIM_MasterSlaveMode_Enable: synchronization between the current timer
+ * and its slaves (through TRGO).
+ * @arg TIM_MasterSlaveMode_Disable: No action
+ * @retval None
+ */
+void TIM_SelectMasterSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_MasterSlaveMode)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST6_PERIPH(TIMx));
+ assert_param(IS_TIM_MSM_STATE(TIM_MasterSlaveMode));
+ /* Reset the MSM Bit */
+ TIMx->SMCR &= (uint16_t)~((uint16_t)TIM_SMCR_MSM);
+
+ /* Set or Reset the MSM Bit */
+ TIMx->SMCR |= TIM_MasterSlaveMode;
+}
+
+/**
+ * @brief Sets the TIMx Counter Register value
+ * @param TIMx: where x can be 1 to 17 to select the TIM peripheral.
+ * @param Counter: specifies the Counter register new value.
+ * @retval None
+ */
+void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+ /* Set the Counter Register value */
+ TIMx->CNT = Counter;
+}
+
+/**
+ * @brief Sets the TIMx Autoreload Register value
+ * @param TIMx: where x can be 1 to 17 to select the TIM peripheral.
+ * @param Autoreload: specifies the Autoreload register new value.
+ * @retval None
+ */
+void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+ /* Set the Autoreload Register value */
+ TIMx->ARR = Autoreload;
+}
+
+/**
+ * @brief Sets the TIMx Capture Compare1 Register value
+ * @param TIMx: where x can be 1 to 17 except 6 and 7 to select the TIM peripheral.
+ * @param Compare1: specifies the Capture Compare1 register new value.
+ * @retval None
+ */
+void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST8_PERIPH(TIMx));
+ /* Set the Capture Compare1 Register value */
+ TIMx->CCR1 = Compare1;
+}
+
+/**
+ * @brief Sets the TIMx Capture Compare2 Register value
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 9, 12 or 15 to select the TIM peripheral.
+ * @param Compare2: specifies the Capture Compare2 register new value.
+ * @retval None
+ */
+void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST6_PERIPH(TIMx));
+ /* Set the Capture Compare2 Register value */
+ TIMx->CCR2 = Compare2;
+}
+
+/**
+ * @brief Sets the TIMx Capture Compare3 Register value
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param Compare3: specifies the Capture Compare3 register new value.
+ * @retval None
+ */
+void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ /* Set the Capture Compare3 Register value */
+ TIMx->CCR3 = Compare3;
+}
+
+/**
+ * @brief Sets the TIMx Capture Compare4 Register value
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param Compare4: specifies the Capture Compare4 register new value.
+ * @retval None
+ */
+void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ /* Set the Capture Compare4 Register value */
+ TIMx->CCR4 = Compare4;
+}
+
+/**
+ * @brief Sets the TIMx Input Capture 1 prescaler.
+ * @param TIMx: where x can be 1 to 17 except 6 and 7 to select the TIM peripheral.
+ * @param TIM_ICPSC: specifies the Input Capture1 prescaler new value.
+ * This parameter can be one of the following values:
+ * @arg TIM_ICPSC_DIV1: no prescaler
+ * @arg TIM_ICPSC_DIV2: capture is done once every 2 events
+ * @arg TIM_ICPSC_DIV4: capture is done once every 4 events
+ * @arg TIM_ICPSC_DIV8: capture is done once every 8 events
+ * @retval None
+ */
+void TIM_SetIC1Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST8_PERIPH(TIMx));
+ assert_param(IS_TIM_IC_PRESCALER(TIM_ICPSC));
+ /* Reset the IC1PSC Bits */
+ TIMx->CCMR1 &= (uint16_t)~((uint16_t)TIM_CCMR1_IC1PSC);
+ /* Set the IC1PSC value */
+ TIMx->CCMR1 |= TIM_ICPSC;
+}
+
+/**
+ * @brief Sets the TIMx Input Capture 2 prescaler.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 9, 12 or 15 to select the TIM peripheral.
+ * @param TIM_ICPSC: specifies the Input Capture2 prescaler new value.
+ * This parameter can be one of the following values:
+ * @arg TIM_ICPSC_DIV1: no prescaler
+ * @arg TIM_ICPSC_DIV2: capture is done once every 2 events
+ * @arg TIM_ICPSC_DIV4: capture is done once every 4 events
+ * @arg TIM_ICPSC_DIV8: capture is done once every 8 events
+ * @retval None
+ */
+void TIM_SetIC2Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST6_PERIPH(TIMx));
+ assert_param(IS_TIM_IC_PRESCALER(TIM_ICPSC));
+ /* Reset the IC2PSC Bits */
+ TIMx->CCMR1 &= (uint16_t)~((uint16_t)TIM_CCMR1_IC2PSC);
+ /* Set the IC2PSC value */
+ TIMx->CCMR1 |= (uint16_t)(TIM_ICPSC << 8);
+}
+
+/**
+ * @brief Sets the TIMx Input Capture 3 prescaler.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_ICPSC: specifies the Input Capture3 prescaler new value.
+ * This parameter can be one of the following values:
+ * @arg TIM_ICPSC_DIV1: no prescaler
+ * @arg TIM_ICPSC_DIV2: capture is done once every 2 events
+ * @arg TIM_ICPSC_DIV4: capture is done once every 4 events
+ * @arg TIM_ICPSC_DIV8: capture is done once every 8 events
+ * @retval None
+ */
+void TIM_SetIC3Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_IC_PRESCALER(TIM_ICPSC));
+ /* Reset the IC3PSC Bits */
+ TIMx->CCMR2 &= (uint16_t)~((uint16_t)TIM_CCMR2_IC3PSC);
+ /* Set the IC3PSC value */
+ TIMx->CCMR2 |= TIM_ICPSC;
+}
+
+/**
+ * @brief Sets the TIMx Input Capture 4 prescaler.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_ICPSC: specifies the Input Capture4 prescaler new value.
+ * This parameter can be one of the following values:
+ * @arg TIM_ICPSC_DIV1: no prescaler
+ * @arg TIM_ICPSC_DIV2: capture is done once every 2 events
+ * @arg TIM_ICPSC_DIV4: capture is done once every 4 events
+ * @arg TIM_ICPSC_DIV8: capture is done once every 8 events
+ * @retval None
+ */
+void TIM_SetIC4Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ assert_param(IS_TIM_IC_PRESCALER(TIM_ICPSC));
+ /* Reset the IC4PSC Bits */
+ TIMx->CCMR2 &= (uint16_t)~((uint16_t)TIM_CCMR2_IC4PSC);
+ /* Set the IC4PSC value */
+ TIMx->CCMR2 |= (uint16_t)(TIM_ICPSC << 8);
+}
+
+/**
+ * @brief Sets the TIMx Clock Division value.
+ * @param TIMx: where x can be 1 to 17 except 6 and 7 to select
+ * the TIM peripheral.
+ * @param TIM_CKD: specifies the clock division value.
+ * This parameter can be one of the following value:
+ * @arg TIM_CKD_DIV1: TDTS = Tck_tim
+ * @arg TIM_CKD_DIV2: TDTS = 2*Tck_tim
+ * @arg TIM_CKD_DIV4: TDTS = 4*Tck_tim
+ * @retval None
+ */
+void TIM_SetClockDivision(TIM_TypeDef* TIMx, uint16_t TIM_CKD)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST8_PERIPH(TIMx));
+ assert_param(IS_TIM_CKD_DIV(TIM_CKD));
+ /* Reset the CKD Bits */
+ TIMx->CR1 &= (uint16_t)~((uint16_t)TIM_CR1_CKD);
+ /* Set the CKD value */
+ TIMx->CR1 |= TIM_CKD;
+}
+
+/**
+ * @brief Gets the TIMx Input Capture 1 value.
+ * @param TIMx: where x can be 1 to 17 except 6 and 7 to select the TIM peripheral.
+ * @retval Capture Compare 1 Register value.
+ */
+uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST8_PERIPH(TIMx));
+ /* Get the Capture 1 Register value */
+ return TIMx->CCR1;
+}
+
+/**
+ * @brief Gets the TIMx Input Capture 2 value.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 9, 12 or 15 to select the TIM peripheral.
+ * @retval Capture Compare 2 Register value.
+ */
+uint16_t TIM_GetCapture2(TIM_TypeDef* TIMx)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST6_PERIPH(TIMx));
+ /* Get the Capture 2 Register value */
+ return TIMx->CCR2;
+}
+
+/**
+ * @brief Gets the TIMx Input Capture 3 value.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @retval Capture Compare 3 Register value.
+ */
+uint16_t TIM_GetCapture3(TIM_TypeDef* TIMx)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ /* Get the Capture 3 Register value */
+ return TIMx->CCR3;
+}
+
+/**
+ * @brief Gets the TIMx Input Capture 4 value.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @retval Capture Compare 4 Register value.
+ */
+uint16_t TIM_GetCapture4(TIM_TypeDef* TIMx)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_LIST3_PERIPH(TIMx));
+ /* Get the Capture 4 Register value */
+ return TIMx->CCR4;
+}
+
+/**
+ * @brief Gets the TIMx Counter value.
+ * @param TIMx: where x can be 1 to 17 to select the TIM peripheral.
+ * @retval Counter Register value.
+ */
+uint16_t TIM_GetCounter(TIM_TypeDef* TIMx)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+ /* Get the Counter Register value */
+ return TIMx->CNT;
+}
+
+/**
+ * @brief Gets the TIMx Prescaler value.
+ * @param TIMx: where x can be 1 to 17 to select the TIM peripheral.
+ * @retval Prescaler Register value.
+ */
+uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+ /* Get the Prescaler Register value */
+ return TIMx->PSC;
+}
+
+/**
+ * @brief Checks whether the specified TIM flag is set or not.
+ * @param TIMx: where x can be 1 to 17 to select the TIM peripheral.
+ * @param TIM_FLAG: specifies the flag to check.
+ * This parameter can be one of the following values:
+ * @arg TIM_FLAG_Update: TIM update Flag
+ * @arg TIM_FLAG_CC1: TIM Capture Compare 1 Flag
+ * @arg TIM_FLAG_CC2: TIM Capture Compare 2 Flag
+ * @arg TIM_FLAG_CC3: TIM Capture Compare 3 Flag
+ * @arg TIM_FLAG_CC4: TIM Capture Compare 4 Flag
+ * @arg TIM_FLAG_COM: TIM Commutation Flag
+ * @arg TIM_FLAG_Trigger: TIM Trigger Flag
+ * @arg TIM_FLAG_Break: TIM Break Flag
+ * @arg TIM_FLAG_CC1OF: TIM Capture Compare 1 overcapture Flag
+ * @arg TIM_FLAG_CC2OF: TIM Capture Compare 2 overcapture Flag
+ * @arg TIM_FLAG_CC3OF: TIM Capture Compare 3 overcapture Flag
+ * @arg TIM_FLAG_CC4OF: TIM Capture Compare 4 overcapture Flag
+ * @note
+ * - TIM6 and TIM7 can have only one update flag.
+ * - TIM9, TIM12 and TIM15 can have only TIM_FLAG_Update, TIM_FLAG_CC1,
+ * TIM_FLAG_CC2 or TIM_FLAG_Trigger.
+ * - TIM10, TIM11, TIM13, TIM14, TIM16 and TIM17 can have TIM_FLAG_Update or TIM_FLAG_CC1.
+ * - TIM_FLAG_Break is used only with TIM1, TIM8 and TIM15.
+ * - TIM_FLAG_COM is used only with TIM1, TIM8, TIM15, TIM16 and TIM17.
+ * @retval The new state of TIM_FLAG (SET or RESET).
+ */
+FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG)
+{
+ ITStatus bitstatus = RESET;
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+ assert_param(IS_TIM_GET_FLAG(TIM_FLAG));
+
+ if ((TIMx->SR & TIM_FLAG) != (uint16_t)RESET)
+ {
+ bitstatus = SET;
+ }
+ else
+ {
+ bitstatus = RESET;
+ }
+ return bitstatus;
+}
+
+/**
+ * @brief Clears the TIMx's pending flags.
+ * @param TIMx: where x can be 1 to 17 to select the TIM peripheral.
+ * @param TIM_FLAG: specifies the flag bit to clear.
+ * This parameter can be any combination of the following values:
+ * @arg TIM_FLAG_Update: TIM update Flag
+ * @arg TIM_FLAG_CC1: TIM Capture Compare 1 Flag
+ * @arg TIM_FLAG_CC2: TIM Capture Compare 2 Flag
+ * @arg TIM_FLAG_CC3: TIM Capture Compare 3 Flag
+ * @arg TIM_FLAG_CC4: TIM Capture Compare 4 Flag
+ * @arg TIM_FLAG_COM: TIM Commutation Flag
+ * @arg TIM_FLAG_Trigger: TIM Trigger Flag
+ * @arg TIM_FLAG_Break: TIM Break Flag
+ * @arg TIM_FLAG_CC1OF: TIM Capture Compare 1 overcapture Flag
+ * @arg TIM_FLAG_CC2OF: TIM Capture Compare 2 overcapture Flag
+ * @arg TIM_FLAG_CC3OF: TIM Capture Compare 3 overcapture Flag
+ * @arg TIM_FLAG_CC4OF: TIM Capture Compare 4 overcapture Flag
+ * @note
+ * - TIM6 and TIM7 can have only one update flag.
+ * - TIM9, TIM12 and TIM15 can have only TIM_FLAG_Update, TIM_FLAG_CC1,
+ * TIM_FLAG_CC2 or TIM_FLAG_Trigger.
+ * - TIM10, TIM11, TIM13, TIM14, TIM16 and TIM17 can have TIM_FLAG_Update or TIM_FLAG_CC1.
+ * - TIM_FLAG_Break is used only with TIM1, TIM8 and TIM15.
+ * - TIM_FLAG_COM is used only with TIM1, TIM8, TIM15, TIM16 and TIM17.
+ * @retval None
+ */
+void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+ assert_param(IS_TIM_CLEAR_FLAG(TIM_FLAG));
+
+ /* Clear the flags */
+ TIMx->SR = (uint16_t)~TIM_FLAG;
+}
+
+/**
+ * @brief Checks whether the TIM interrupt has occurred or not.
+ * @param TIMx: where x can be 1 to 17 to select the TIM peripheral.
+ * @param TIM_IT: specifies the TIM interrupt source to check.
+ * This parameter can be one of the following values:
+ * @arg TIM_IT_Update: TIM update Interrupt source
+ * @arg TIM_IT_CC1: TIM Capture Compare 1 Interrupt source
+ * @arg TIM_IT_CC2: TIM Capture Compare 2 Interrupt source
+ * @arg TIM_IT_CC3: TIM Capture Compare 3 Interrupt source
+ * @arg TIM_IT_CC4: TIM Capture Compare 4 Interrupt source
+ * @arg TIM_IT_COM: TIM Commutation Interrupt source
+ * @arg TIM_IT_Trigger: TIM Trigger Interrupt source
+ * @arg TIM_IT_Break: TIM Break Interrupt source
+ * @note
+ * - TIM6 and TIM7 can generate only an update interrupt.
+ * - TIM9, TIM12 and TIM15 can have only TIM_IT_Update, TIM_IT_CC1,
+ * TIM_IT_CC2 or TIM_IT_Trigger.
+ * - TIM10, TIM11, TIM13, TIM14, TIM16 and TIM17 can have TIM_IT_Update or TIM_IT_CC1.
+ * - TIM_IT_Break is used only with TIM1, TIM8 and TIM15.
+ * - TIM_IT_COM is used only with TIM1, TIM8, TIM15, TIM16 and TIM17.
+ * @retval The new state of the TIM_IT(SET or RESET).
+ */
+ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT)
+{
+ ITStatus bitstatus = RESET;
+ uint16_t itstatus = 0x0, itenable = 0x0;
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+ assert_param(IS_TIM_GET_IT(TIM_IT));
+
+ itstatus = TIMx->SR & TIM_IT;
+
+ itenable = TIMx->DIER & TIM_IT;
+ if ((itstatus != (uint16_t)RESET) && (itenable != (uint16_t)RESET))
+ {
+ bitstatus = SET;
+ }
+ else
+ {
+ bitstatus = RESET;
+ }
+ return bitstatus;
+}
+
+/**
+ * @brief Clears the TIMx's interrupt pending bits.
+ * @param TIMx: where x can be 1 to 17 to select the TIM peripheral.
+ * @param TIM_IT: specifies the pending bit to clear.
+ * This parameter can be any combination of the following values:
+ * @arg TIM_IT_Update: TIM1 update Interrupt source
+ * @arg TIM_IT_CC1: TIM Capture Compare 1 Interrupt source
+ * @arg TIM_IT_CC2: TIM Capture Compare 2 Interrupt source
+ * @arg TIM_IT_CC3: TIM Capture Compare 3 Interrupt source
+ * @arg TIM_IT_CC4: TIM Capture Compare 4 Interrupt source
+ * @arg TIM_IT_COM: TIM Commutation Interrupt source
+ * @arg TIM_IT_Trigger: TIM Trigger Interrupt source
+ * @arg TIM_IT_Break: TIM Break Interrupt source
+ * @note
+ * - TIM6 and TIM7 can generate only an update interrupt.
+ * - TIM9, TIM12 and TIM15 can have only TIM_IT_Update, TIM_IT_CC1,
+ * TIM_IT_CC2 or TIM_IT_Trigger.
+ * - TIM10, TIM11, TIM13, TIM14, TIM16 and TIM17 can have TIM_IT_Update or TIM_IT_CC1.
+ * - TIM_IT_Break is used only with TIM1, TIM8 and TIM15.
+ * - TIM_IT_COM is used only with TIM1, TIM8, TIM15, TIM16 and TIM17.
+ * @retval None
+ */
+void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT)
+{
+ /* Check the parameters */
+ assert_param(IS_TIM_ALL_PERIPH(TIMx));
+ assert_param(IS_TIM_IT(TIM_IT));
+ /* Clear the IT pending Bit */
+ TIMx->SR = (uint16_t)~TIM_IT;
+}
+
+/**
+ * @brief Configure the TI1 as Input.
+ * @param TIMx: where x can be 1 to 17 except 6 and 7 to select the TIM peripheral.
+ * @param TIM_ICPolarity : The Input Polarity.
+ * This parameter can be one of the following values:
+ * @arg TIM_ICPolarity_Rising
+ * @arg TIM_ICPolarity_Falling
+ * @param TIM_ICSelection: specifies the input to be used.
+ * This parameter can be one of the following values:
+ * @arg TIM_ICSelection_DirectTI: TIM Input 1 is selected to be connected to IC1.
+ * @arg TIM_ICSelection_IndirectTI: TIM Input 1 is selected to be connected to IC2.
+ * @arg TIM_ICSelection_TRC: TIM Input 1 is selected to be connected to TRC.
+ * @param TIM_ICFilter: Specifies the Input Capture Filter.
+ * This parameter must be a value between 0x00 and 0x0F.
+ * @retval None
+ */
+static void TI1_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection,
+ uint16_t TIM_ICFilter)
+{
+ uint16_t tmpccmr1 = 0, tmpccer = 0;
+ /* Disable the Channel 1: Reset the CC1E Bit */
+ TIMx->CCER &= (uint16_t)~((uint16_t)TIM_CCER_CC1E);
+ tmpccmr1 = TIMx->CCMR1;
+ tmpccer = TIMx->CCER;
+ /* Select the Input and set the filter */
+ tmpccmr1 &= (uint16_t)(((uint16_t)~((uint16_t)TIM_CCMR1_CC1S)) & ((uint16_t)~((uint16_t)TIM_CCMR1_IC1F)));
+ tmpccmr1 |= (uint16_t)(TIM_ICSelection | (uint16_t)(TIM_ICFilter << (uint16_t)4));
+
+ if((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM2) || (TIMx == TIM3) ||
+ (TIMx == TIM4) ||(TIMx == TIM5))
+ {
+ /* Select the Polarity and set the CC1E Bit */
+ tmpccer &= (uint16_t)~((uint16_t)(TIM_CCER_CC1P));
+ tmpccer |= (uint16_t)(TIM_ICPolarity | (uint16_t)TIM_CCER_CC1E);
+ }
+ else
+ {
+ /* Select the Polarity and set the CC1E Bit */
+ tmpccer &= (uint16_t)~((uint16_t)(TIM_CCER_CC1P | TIM_CCER_CC1NP));
+ tmpccer |= (uint16_t)(TIM_ICPolarity | (uint16_t)TIM_CCER_CC1E);
+ }
+
+ /* Write to TIMx CCMR1 and CCER registers */
+ TIMx->CCMR1 = tmpccmr1;
+ TIMx->CCER = tmpccer;
+}
+
+/**
+ * @brief Configure the TI2 as Input.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5, 8, 9, 12 or 15 to select the TIM peripheral.
+ * @param TIM_ICPolarity : The Input Polarity.
+ * This parameter can be one of the following values:
+ * @arg TIM_ICPolarity_Rising
+ * @arg TIM_ICPolarity_Falling
+ * @param TIM_ICSelection: specifies the input to be used.
+ * This parameter can be one of the following values:
+ * @arg TIM_ICSelection_DirectTI: TIM Input 2 is selected to be connected to IC2.
+ * @arg TIM_ICSelection_IndirectTI: TIM Input 2 is selected to be connected to IC1.
+ * @arg TIM_ICSelection_TRC: TIM Input 2 is selected to be connected to TRC.
+ * @param TIM_ICFilter: Specifies the Input Capture Filter.
+ * This parameter must be a value between 0x00 and 0x0F.
+ * @retval None
+ */
+static void TI2_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection,
+ uint16_t TIM_ICFilter)
+{
+ uint16_t tmpccmr1 = 0, tmpccer = 0, tmp = 0;
+ /* Disable the Channel 2: Reset the CC2E Bit */
+ TIMx->CCER &= (uint16_t)~((uint16_t)TIM_CCER_CC2E);
+ tmpccmr1 = TIMx->CCMR1;
+ tmpccer = TIMx->CCER;
+ tmp = (uint16_t)(TIM_ICPolarity << 4);
+ /* Select the Input and set the filter */
+ tmpccmr1 &= (uint16_t)(((uint16_t)~((uint16_t)TIM_CCMR1_CC2S)) & ((uint16_t)~((uint16_t)TIM_CCMR1_IC2F)));
+ tmpccmr1 |= (uint16_t)(TIM_ICFilter << 12);
+ tmpccmr1 |= (uint16_t)(TIM_ICSelection << 8);
+
+ if((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM2) || (TIMx == TIM3) ||
+ (TIMx == TIM4) ||(TIMx == TIM5))
+ {
+ /* Select the Polarity and set the CC2E Bit */
+ tmpccer &= (uint16_t)~((uint16_t)(TIM_CCER_CC2P));
+ tmpccer |= (uint16_t)(tmp | (uint16_t)TIM_CCER_CC2E);
+ }
+ else
+ {
+ /* Select the Polarity and set the CC2E Bit */
+ tmpccer &= (uint16_t)~((uint16_t)(TIM_CCER_CC2P | TIM_CCER_CC2NP));
+ tmpccer |= (uint16_t)(TIM_ICPolarity | (uint16_t)TIM_CCER_CC2E);
+ }
+
+ /* Write to TIMx CCMR1 and CCER registers */
+ TIMx->CCMR1 = tmpccmr1 ;
+ TIMx->CCER = tmpccer;
+}
+
+/**
+ * @brief Configure the TI3 as Input.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_ICPolarity : The Input Polarity.
+ * This parameter can be one of the following values:
+ * @arg TIM_ICPolarity_Rising
+ * @arg TIM_ICPolarity_Falling
+ * @param TIM_ICSelection: specifies the input to be used.
+ * This parameter can be one of the following values:
+ * @arg TIM_ICSelection_DirectTI: TIM Input 3 is selected to be connected to IC3.
+ * @arg TIM_ICSelection_IndirectTI: TIM Input 3 is selected to be connected to IC4.
+ * @arg TIM_ICSelection_TRC: TIM Input 3 is selected to be connected to TRC.
+ * @param TIM_ICFilter: Specifies the Input Capture Filter.
+ * This parameter must be a value between 0x00 and 0x0F.
+ * @retval None
+ */
+static void TI3_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection,
+ uint16_t TIM_ICFilter)
+{
+ uint16_t tmpccmr2 = 0, tmpccer = 0, tmp = 0;
+ /* Disable the Channel 3: Reset the CC3E Bit */
+ TIMx->CCER &= (uint16_t)~((uint16_t)TIM_CCER_CC3E);
+ tmpccmr2 = TIMx->CCMR2;
+ tmpccer = TIMx->CCER;
+ tmp = (uint16_t)(TIM_ICPolarity << 8);
+ /* Select the Input and set the filter */
+ tmpccmr2 &= (uint16_t)(((uint16_t)~((uint16_t)TIM_CCMR2_CC3S)) & ((uint16_t)~((uint16_t)TIM_CCMR2_IC3F)));
+ tmpccmr2 |= (uint16_t)(TIM_ICSelection | (uint16_t)(TIM_ICFilter << (uint16_t)4));
+
+ if((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM2) || (TIMx == TIM3) ||
+ (TIMx == TIM4) ||(TIMx == TIM5))
+ {
+ /* Select the Polarity and set the CC3E Bit */
+ tmpccer &= (uint16_t)~((uint16_t)(TIM_CCER_CC3P));
+ tmpccer |= (uint16_t)(tmp | (uint16_t)TIM_CCER_CC3E);
+ }
+ else
+ {
+ /* Select the Polarity and set the CC3E Bit */
+ tmpccer &= (uint16_t)~((uint16_t)(TIM_CCER_CC3P | TIM_CCER_CC3NP));
+ tmpccer |= (uint16_t)(TIM_ICPolarity | (uint16_t)TIM_CCER_CC3E);
+ }
+
+ /* Write to TIMx CCMR2 and CCER registers */
+ TIMx->CCMR2 = tmpccmr2;
+ TIMx->CCER = tmpccer;
+}
+
+/**
+ * @brief Configure the TI4 as Input.
+ * @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
+ * @param TIM_ICPolarity : The Input Polarity.
+ * This parameter can be one of the following values:
+ * @arg TIM_ICPolarity_Rising
+ * @arg TIM_ICPolarity_Falling
+ * @param TIM_ICSelection: specifies the input to be used.
+ * This parameter can be one of the following values:
+ * @arg TIM_ICSelection_DirectTI: TIM Input 4 is selected to be connected to IC4.
+ * @arg TIM_ICSelection_IndirectTI: TIM Input 4 is selected to be connected to IC3.
+ * @arg TIM_ICSelection_TRC: TIM Input 4 is selected to be connected to TRC.
+ * @param TIM_ICFilter: Specifies the Input Capture Filter.
+ * This parameter must be a value between 0x00 and 0x0F.
+ * @retval None
+ */
+static void TI4_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection,
+ uint16_t TIM_ICFilter)
+{
+ uint16_t tmpccmr2 = 0, tmpccer = 0, tmp = 0;
+
+ /* Disable the Channel 4: Reset the CC4E Bit */
+ TIMx->CCER &= (uint16_t)~((uint16_t)TIM_CCER_CC4E);
+ tmpccmr2 = TIMx->CCMR2;
+ tmpccer = TIMx->CCER;
+ tmp = (uint16_t)(TIM_ICPolarity << 12);
+ /* Select the Input and set the filter */
+ tmpccmr2 &= (uint16_t)((uint16_t)(~(uint16_t)TIM_CCMR2_CC4S) & ((uint16_t)~((uint16_t)TIM_CCMR2_IC4F)));
+ tmpccmr2 |= (uint16_t)(TIM_ICSelection << 8);
+ tmpccmr2 |= (uint16_t)(TIM_ICFilter << 12);
+
+ if((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM2) || (TIMx == TIM3) ||
+ (TIMx == TIM4) ||(TIMx == TIM5))
+ {
+ /* Select the Polarity and set the CC4E Bit */
+ tmpccer &= (uint16_t)~((uint16_t)(TIM_CCER_CC4P));
+ tmpccer |= (uint16_t)(tmp | (uint16_t)TIM_CCER_CC4E);
+ }
+ else
+ {
+ /* Select the Polarity and set the CC4E Bit */
+ tmpccer &= (uint16_t)~((uint16_t)(TIM_CCER_CC3P | TIM_CCER_CC4NP));
+ tmpccer |= (uint16_t)(TIM_ICPolarity | (uint16_t)TIM_CCER_CC4E);
+ }
+ /* Write to TIMx CCMR2 and CCER registers */
+ TIMx->CCMR2 = tmpccmr2;
+ TIMx->CCER = tmpccer;
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
diff --git a/stm_lib/src/stm32f10x_usart.c b/stm_lib/src/stm32f10x_usart.c
new file mode 100644
index 00000000..e794eae6
--- /dev/null
+++ b/stm_lib/src/stm32f10x_usart.c
@@ -0,0 +1,1058 @@
+/**
+ ******************************************************************************
+ * @file stm32f10x_usart.c
+ * @author MCD Application Team
+ * @version V3.5.0
+ * @date 11-March-2011
+ * @brief This file provides all the USART firmware functions.
+ ******************************************************************************
+ * @attention
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ *