diff --git a/.github/workflows/stale-issue-bot.yaml b/.github/workflows/stale-issue-bot.yaml index 3720e72cf4f6..b6369d8dced0 100644 --- a/.github/workflows/stale-issue-bot.yaml +++ b/.github/workflows/stale-issue-bot.yaml @@ -332,7 +332,7 @@ jobs: if: github.repository == 'Klipper3d/klipper' runs-on: ubuntu-latest steps: - - uses: dessant/lock-threads@v3 + - uses: dessant/lock-threads@v4 with: issue-inactive-days: '180' issue-lock-reason: '' diff --git a/config/generic-bigtreetech-manta-m8p-v1.0.cfg b/config/generic-bigtreetech-manta-m8p-v1.0.cfg index 0ed4c9f0e8ae..2a801cded459 100644 --- a/config/generic-bigtreetech-manta-m8p-v1.0.cfg +++ b/config/generic-bigtreetech-manta-m8p-v1.0.cfg @@ -43,7 +43,7 @@ position_max: 270 #[stepper_] #step_pin: PD3 #dir_pin: PD2 -#enable_pin: PD5 +#enable_pin: !PD5 #endstop_pin: PC0 #... diff --git a/config/generic-bigtreetech-manta-m8p-v1.1.cfg b/config/generic-bigtreetech-manta-m8p-v1.1.cfg index 6a08145147fa..36ef710cde07 100644 --- a/config/generic-bigtreetech-manta-m8p-v1.1.cfg +++ b/config/generic-bigtreetech-manta-m8p-v1.1.cfg @@ -44,7 +44,7 @@ position_max: 270 #[stepper_] #step_pin: PD3 #dir_pin: PD2 -#enable_pin: PD5 +#enable_pin: !PD5 #endstop_pin: PC0 #... diff --git a/config/generic-bigtreetech-skr-3.cfg b/config/generic-bigtreetech-skr-3.cfg index c769ae0399af..97570cd514fc 100644 --- a/config/generic-bigtreetech-skr-3.cfg +++ b/config/generic-bigtreetech-skr-3.cfg @@ -1,6 +1,8 @@ # This file contains common pin mappings for the BigTreeTech SKR 3. +# This board can ship with one of two chips, STM32H743 or STM32H723. # To use this config, during "make menuconfig" enable "low-level -# options", "STM32H743", "128KiB bootloader", and "25MHz clock". +# options", "STM32H743" or "STM32H723", "128KiB bootloader", +# and "25MHz clock". # See docs/Config_Reference.md for a description of parameters. diff --git a/config/printer-anycubic-kobra-go-2022.cfg b/config/printer-anycubic-kobra-go-2022.cfg new file mode 100644 index 000000000000..525a50bd2837 --- /dev/null +++ b/config/printer-anycubic-kobra-go-2022.cfg @@ -0,0 +1,133 @@ +# This file contains a configuration for the Anycubic Kobra Go printer. +# +# See docs/Config_Reference.md for a description of parameters. +# +# To build the firmware, use the following configuration: +# - Micro-controller: Huada Semiconductor HC32F460 +# - Communication interface: Serial (PA3 & PA2) - Anycubic +# +# Installation: +# 1. Rename the klipper bin to `firmware.bin` and copy it to an SD Card. +# 2. Power off the Printer, insert the SD Card and power it on. +# 3. The the LCD will be stuck on the Firmware-update screen. +# Just Wait for 3-5 minutes to ensure the firmware is flashed. +# 4. After waiting, shutdown the printer and remove the SD Card. + +[stepper_x] +step_pin: PA12 +dir_pin: PA11 +enable_pin: !PA15 +microsteps: 16 +rotation_distance: 40 +endstop_pin: !PH2 +position_endstop: -13 +position_min:-13 +position_max: 238 +homing_speed: 50 + +[stepper_y] +step_pin: PA9 +dir_pin: PA8 +enable_pin: !PA15 +microsteps: 16 +rotation_distance: 40 +endstop_pin: ^!PC13 +position_endstop: -9 +position_min:-9 +position_max: 238 +homing_speed: 50 + +[stepper_z] +step_pin: PC7 +dir_pin: !PC6 +enable_pin: !PA15 +microsteps: 16 +rotation_distance: 8 +endstop_pin: ^PC14 +position_endstop: 0 +position_min: -10 +position_max: 250 +homing_speed: 5 + +[extruder] +step_pin: PB15 +dir_pin: PB14 +enable_pin: !PA15 +microsteps: 16 +rotation_distance: 31.07 +max_extrude_only_velocity: 25 +max_extrude_only_accel: 1000 +nozzle_diameter: 0.400 +filament_diameter: 1.750 +heater_pin: PB8 +sensor_type: ATC Semitec 104GT-2 +sensor_pin: PC3 +min_extrude_temp: 170 +min_temp: 0 +max_temp: 250 +control: pid +pid_kp: 19.56 +pid_ki: 1.62 +pid_kd: 200.00 + +[heater_bed] +heater_pin: PB9 +sensor_type: EPCOS 100K B57560G104F +sensor_pin: PC1 +min_temp: 0 +max_temp: 120 +control: pid +pid_kp: 97.1 +pid_ki: 1.41 +pid_kd: 1675.16 + +[bed_mesh] +speed: 200 +horizontal_move_z: 2.5 +mesh_min: 5, 5 +mesh_max: 217.2, 207.8 +probe_count: 5, 5 + +[probe] +pin: PA1 +x_offset: -20.8 +y_offset: 0 +z_offset: 0 +samples: 3 +samples_result: average +samples_tolerance_retries: 3 +sample_retract_dist: 0.5 +speed: 2 +lift_speed: 4 + +[safe_z_home] +home_xy_position: 0, 0 +speed: 5 +z_hop: 10 +z_hop_speed: 15 + +[controller_fan controller_fan] +pin: PB12 + +[heater_fan extruder_fan] +pin: PB13 + +[fan] +pin: PB5 +cycle_time: 0.00005 #20kHz + +[output_pin enable_pin] +pin: PB6 +static_value: 1 + #This pin enables the bed, hotend, extruder fan, part fan. + +[mcu] +serial: /dev/serial/by-id/usb-1a86_USB_Serial-if00-port0 +restart_method: command + +[printer] +kinematics: cartesian +max_velocity: 300 +max_accel: 500 +max_z_velocity: 4 +max_z_accel: 100 diff --git a/config/printer-ratrig-v-minion-2021.cfg b/config/printer-ratrig-v-minion-2021.cfg new file mode 100644 index 000000000000..d50d6462f9fc --- /dev/null +++ b/config/printer-ratrig-v-minion-2021.cfg @@ -0,0 +1,180 @@ +# This file contains pin mappings for a full Ratrig V-Minion kit +# with an Octopus Pro v1.1 board. +# +# This will not work with RatOS +# +# To use this config, during "make menuconfig" select the STM32F446 +# with a "32KiB bootloader", USB (on PA11/PA12) communication, and +# a "12MHZ Crystal" +# +# Flash this firmware on the MCU by copying "out/klipper.bin" to an SD +# card and turning the printer on with the card inserted. The firmware +# filename must be named "firmware.bin" +# +# See docs/Config_Reference.md for a description of parameters. + +[stepper_x] +step_pin: PF13 +dir_pin: !PF12 +enable_pin: !PF14 +endstop_pin: ^PG6 +rotation_distance: 40 +microsteps: 64 +position_max: 180 +position_min: 0 +homing_speed: 60 +position_endstop: 0 + +[tmc2209 stepper_x] +uart_pin: PC4 +run_current: 0.8 +interpolate: false +stealthchop_threshold: 0 + +[stepper_y] +step_pin: PG0 +dir_pin: PG1 +enable_pin: !PF15 +endstop_pin: ^PG9 +rotation_distance: 40 +microsteps: 64 +position_max: 180 +position_min: 0 +homing_speed: 60 +position_endstop: 0 + +[tmc2209 stepper_y] +uart_pin: PD11 +run_current: 0.8 +interpolate: false +stealthchop_threshold: 0 + +[stepper_z] +step_pin: PC13 +dir_pin: !PF0 +enable_pin: !PF1 +endstop_pin: probe:z_virtual_endstop +rotation_distance: 4 +position_min: -5 +microsteps: 64 +position_max: 180 + +[tmc2209 stepper_z] +uart_pin: PE4 +run_current: 0.8 +interpolate: false +stealthchop_threshold: 0 + +[extruder] +rotation_distance: 5.57 +full_steps_per_rotation: 200 +filament_diameter: 1.750 +step_pin: PF11 +dir_pin: !PG3 +enable_pin: !PG5 +microsteps: 64 +nozzle_diameter: 0.4 +heater_pin: PA2 +sensor_type: Generic 3950 +sensor_pin: PF4 +control: pid +pid_Kp: 22.2 +pid_Ki: 1.08 +pid_Kd: 114 + +min_temp: 0 +max_temp: 290 + +[tmc2209 extruder] +uart_pin: PC6 +run_current: 0.70 +stealthchop_threshold: 0 +interpolate: False + +[probe] +pin: ^PB7 +x_offset: -24.0 +y_offset: -13.0 +z_offset: 0.0 +speed: 5 +samples: 2 +sample_retract_dist: 2 +lift_speed: 5.0 +samples_result: median +samples_tolerance: 0.02 +samples_tolerance_retries: 5 + +[bed_mesh] +speed: 300 +horizontal_move_z: 5 +mesh_min: 15,15 +mesh_max: 150,160 +probe_count: 5,5 +fade_start: 1.0 +fade_end: 10.0 +mesh_pps: 2,2 +algorithm: bicubic +bicubic_tension: .2 + +[screws_tilt_adjust] +screw1: 80, 108 +screw1_name: Left Screw +screw2: 155, 72 +screw2_name: Front Right Screw +screw3: 155, 147 +screw3_name: Rear Right Screw +horizontal_move_z: 10 +speed: 300 +screw_thread: CCW-M4 + +[safe_z_home] +home_xy_position: 90,90 +z_hop: 5 +speed: 300 + +[heater_bed] +heater_pin: PA1 +sensor_type: EPCOS 100K B57560G104F +sensor_pin: PF3 +control: pid +pid_kp: 54.027 +pid_ki: 0.770 +pid_kd: 948.182 +min_temp: 0 +max_temp: 120 + +[fan] +pin: PA8 +shutdown_speed: 0.0 + +[heater_fan hotend_cooling_fan] +pin: PE5 +fan_speed: 1.0 +heater: extruder +heater_temp: 50.0 + +[controller_fan controller_fan] +pin: PD12 +fan_speed: 1.0 +stepper: stepper_x, stepper_y, stepper_z + +[printer] +kinematics: cartesian +max_velocity: 500 +max_accel: 20000 +max_z_velocity: 15 +max_z_accel: 2000 + +[mcu] +serial: INSERTSERIALIDHERE + +[board_pins octopus_11_tmc2209] +aliases: +## Expansion ports + # EXP1 header + EXP1_1=PE8, EXP1_3=PE9, EXP1_5=PE12, EXP1_7=PE14, EXP1_9=, + EXP1_2=PE7, EXP1_4=PE10, EXP1_6=PE13, EXP1_8=PE15, EXP1_10=<5V>, + # EXP2 header + EXP2_1=PA6, EXP2_3=PB1, EXP2_5=PB2, EXP2_7=PC15, EXP2_9=, + EXP2_2=PA5, EXP2_4=PA4, EXP2_6=PA7, EXP2_8=, EXP2_10=PC5, + # Pins EXP2_1, EXP2_6, EXP2_2 are also MISO, MOSI, SCK of bus "spi2" diff --git a/config/printer-sovol-sv05-2022.cfg b/config/printer-sovol-sv05-2022.cfg new file mode 100644 index 000000000000..dafc6f3cf322 --- /dev/null +++ b/config/printer-sovol-sv05-2022.cfg @@ -0,0 +1,144 @@ +# This file contains pin mappings for the stock 2022 Sovol SV05 +# with the 32-bit Creality 4.2.2 board. +# +# To use this config, during "make menuconfig" select the STM32F103 +# with a "28KiB bootloader" and serial (on USART1 PA10/PA9) +# communication. +# +# Flash this firmware by copying "out/klipper.bin" to a SD card and +# turning on the printer with the card inserted. The firmware +# filename must end in ".bin" and must not match the last filename +# that was flashed. Might need a renaming if printer dosnt flash. + +# See docs/Config_Reference.md for a description of parameters. +[mcu] +serial: /dev/serial/by-id/usb-1a86_USB_Serial-if00-port0 +restart_method: command + +[printer] +kinematics: cartesian +max_velocity: 300 +max_accel: 1000 +max_accel_to_decel: 1000 +max_z_velocity: 5 +max_z_accel: 100 + +[stepper_x] +step_pin: PC2 +dir_pin: PB9 +enable_pin: !PC3 +microsteps: 16 +rotation_distance: 40 +endstop_pin: ^PA5 +position_endstop: 220 +position_max: 220 +homing_speed: 50 +position_min: -4 + +[stepper_y] +step_pin: PB8 +dir_pin: PB7 +enable_pin: !PC3 +microsteps: 16 +rotation_distance: 40 +endstop_pin: ^PA6 +position_endstop: 220 +position_max: 220 +position_min: -4 +homing_speed: 50 + +[stepper_z] +step_pin: PB6 +dir_pin: PB5 +enable_pin: !PC3 +microsteps: 16 +rotation_distance: 8 +endstop_pin: probe:z_virtual_endstop +position_max: 300 +position_min: -3 + +[heater_bed] +heater_pin: PA2 +sensor_type: EPCOS 100K B57560G104F +sensor_pin: PC4 +min_temp: 0 +max_temp: 130 +control: pid +pid_kp: 64.742 +pid_ki: 0.827 +pid_kd: 1267.326 + +[fan] +pin: PA0 + +[safe_z_home] +home_xy_position: 70, 103 +speed: 100 +z_hop: 10 +z_hop_speed: 20 + +[extruder] +step_pin: PB4 +dir_pin: PB3 +enable_pin: !PC3 +microsteps: 16 +rotation_distance: 7.394 +nozzle_diameter: 0.400 +filament_diameter: 1.750 +max_extrude_only_distance: 100.0 +heater_pin: PA1 +sensor_type: EPCOS 100K B57560G104F +sensor_pin: PC5 +min_temp: 0 +max_temp: 280 +control: pid +pid_kp: 28.850 +pid_ki: 1.658 +pid_kd: 125.496 + +[bltouch] +sensor_pin: ^PB1 +control_pin: PB0 +z_offset: 0 +x_offset: 40 +y_offset: 7 +samples: 2 +samples_tolerance: 0.015 +samples_tolerance_retries: 5 + +[bed_mesh] +speed: 100 +horizontal_move_z: 5 +mesh_min: 40, 7 +mesh_max: 220, 220 +probe_count: 5, 5 +algorithm: bicubic +fade_start: 1 +fade_end: 10 + +[bed_screws] +screw1: 25,28 +screw2: 195,28 +screw3: 195,197 +screw4: 25,197 + +[screws_tilt_adjust] +screw1: -4,21 +screw1_name: front left screw +screw2: 155,21 +screw2_name: front right screw +screw3: 155,190 +screw3_name: rear right screw +screw4: -4,190 +screw4_name: rear left screw +horizontal_move_z: 10 +speed: 50 +screw_thread: CW-M4 + +[display] +lcd_type: st7920 +cs_pin: PB12 +sclk_pin: PB13 +sid_pin: PB15 +encoder_pins: ^PB14, ^PB10 +click_pin: ^!PB2 diff --git a/config/printer-voxelab-aquila-2021.cfg b/config/printer-voxelab-aquila-2021.cfg new file mode 100644 index 000000000000..a23d00c6f01a --- /dev/null +++ b/config/printer-voxelab-aquila-2021.cfg @@ -0,0 +1,84 @@ +# This file contains pin mappings for the Voxelab Aquila +# with the FFP0173 1.0.1 mainboard. To use this config, during +# "make menuconfig" select the STM32F103 for STM32/G32, or +# Nation N32G452 for N32 version, 28KB boot, serial PA9/PA10. + +# See docs/Config_Reference.md for a description of parameters. + +[stepper_x] +step_pin: PC2 +dir_pin: PB9 +enable_pin: !PC3 +microsteps: 16 +rotation_distance: 40 +endstop_pin: ^PA5 +position_endstop: 0 +position_max: 235 +homing_speed: 50 + +[stepper_y] +step_pin: PB8 +dir_pin: PB7 +enable_pin: !PC3 +microsteps: 16 +rotation_distance: 40 +endstop_pin: ^PA6 +position_endstop: 0 +position_max: 235 +homing_speed: 50 + +[stepper_z] +step_pin: PB6 +dir_pin: !PB5 +enable_pin: !PC3 +microsteps: 16 +rotation_distance: 8 +endstop_pin: ^PA7 +position_endstop: 0.0 +position_max: 250 + +[extruder] +max_extrude_only_distance: 100.0 +step_pin: PB4 +dir_pin: PB3 +enable_pin: !PC3 +microsteps: 16 +rotation_distance: 34.406 +nozzle_diameter: 0.400 +filament_diameter: 1.750 +heater_pin: PA1 +sensor_type: EPCOS 100K B57560G104F +sensor_pin: PC5 +control: pid +# tuned for stock hardware with 200 degree Celsius target +pid_Kp: 21.527 +pid_Ki: 1.063 +pid_Kd: 108.982 +min_temp: 0 +max_temp: 250 + +[heater_bed] +heater_pin: PA2 +sensor_type: EPCOS 100K B57560G104F +sensor_pin: PC4 +control: pid +# tuned for stock hardware with 50 degree Celsius target +pid_Kp: 54.027 +pid_Ki: 0.770 +pid_Kd: 948.182 +min_temp: 0 +max_temp: 130 + +[fan] +pin: PA0 + +[mcu] +serial: /dev/serial/by-id/usb-1a86_USB_Serial-if00-port0 +restart_method: command + +[printer] +kinematics: cartesian +max_velocity: 300 +max_accel: 3000 +max_z_velocity: 5 +max_z_accel: 100 diff --git a/docs/Bed_Mesh.md b/docs/Bed_Mesh.md index cdae4cbde19a..c45ca2ab2f51 100644 --- a/docs/Bed_Mesh.md +++ b/docs/Bed_Mesh.md @@ -371,7 +371,7 @@ following parameters are available: - `MESH_ORIGIN` - `ROUND_PROBE_COUNT` - All beds: - - `RELATIVE_REFERNCE_INDEX` + - `RELATIVE_REFERENCE_INDEX` - `ALGORITHM` See the configuration documentation above for details on how each parameter diff --git a/docs/Config_Changes.md b/docs/Config_Changes.md index efe962d1a77f..14c3b12bfbda 100644 --- a/docs/Config_Changes.md +++ b/docs/Config_Changes.md @@ -8,6 +8,9 @@ All dates in this document are approximate. ## Changes +20230407: The `stalled_bytes` counter in the log and in the +`printer.mcu.last_stats` field has been renamed to `upcoming_bytes`. + 20230304: The `SET_TMC_CURRENT` command now properly adjusts the globalscaler register for drivers that have it. This removes a limitation where on tmc5160, the currents could not be raised higher with `SET_TMC_CURRENT` than the diff --git a/docs/Config_Reference.md b/docs/Config_Reference.md index 4e6488476149..dd4449567699 100644 --- a/docs/Config_Reference.md +++ b/docs/Config_Reference.md @@ -2375,6 +2375,30 @@ sensor_type: BME280 # above parameters. ``` +### AHT10/AHT20/AHT21 temperature sensor + +AHT10/AHT20/AHT21 two wire interface (I2C) environmental sensors. +Note that these sensors are not intended for use with extruders and +heater beds, but rather for monitoring ambient temperature (C) and +relative humidity. See +[sample-macros.cfg](../config/sample-macros.cfg) for a gcode_macro +that may be used to report humidity in addition to temperature. + +``` +sensor_type: AHT10 +# Also use AHT10 for AHT20 and AHT21 sensors. +#i2c_address: +# Default is 56 (0x38). Some AHT10 sensors give the option to use +# 57 (0x39) by moving a resistor. +#i2c_mcu: +#i2c_bus: +#i2c_speed: +# See the "common I2C settings" section for a description of the +# above parameters. +#aht10_report_time: +# Interval in seconds between readings. Default is 30, minimum is 5 +``` + ### HTU21D sensor HTU21D family two wire interface (I2C) environmental sensor. Note that @@ -3410,6 +3434,7 @@ run_current: #driver_SEDN: 0 #driver_SEIMIN: 0 #driver_SFILT: 0 +#driver_SG4_ANGLE_OFFSET: 1 # Set the given register during the configuration of the TMC2240 # chip. This may be used to set custom motor parameters. The # defaults for each parameter are next to the parameter name in the @@ -3523,6 +3548,10 @@ run_current: #driver_SEDN: 0 #driver_SEIMIN: 0 #driver_SFILT: 0 +#driver_DRVSTRENGTH: 0 +#driver_BBMCLKS: 4 +#driver_BBMTIME: 0 +#driver_FILT_ISENSE: 0 # Set the given register during the configuration of the TMC5160 # chip. This may be used to set custom motor parameters. The # defaults for each parameter are next to the parameter name in the diff --git a/docs/G-Codes.md b/docs/G-Codes.md index b28f8ab66985..d89c7df8cd72 100644 --- a/docs/G-Codes.md +++ b/docs/G-Codes.md @@ -1219,8 +1219,9 @@ The following commands are available when any of the are enabled. #### DUMP_TMC -`DUMP_TMC STEPPER=`: This command will read the TMC driver -registers and report their values. +`DUMP_TMC STEPPER= [REGISTER=]`: This command will read all TMC +driver registers and report their values. If a REGISTER is provided, only +the specified register will be dumped. #### INIT_TMC `INIT_TMC STEPPER=`: This command will initialize the TMC diff --git a/docs/Measuring_Resonances.md b/docs/Measuring_Resonances.md index 63b61394774d..17a3756251aa 100644 --- a/docs/Measuring_Resonances.md +++ b/docs/Measuring_Resonances.md @@ -1,35 +1,60 @@ # Measuring Resonances -Klipper has built-in support for ADXL345 accelerometer, which can be used to -measure resonance frequencies of the printer for different axes, and auto-tune -[input shapers](Resonance_Compensation.md) to compensate for resonances. -Note that using ADXL345 requires some soldering and crimping. ADXL345 can be -connected to a Raspberry Pi directly, or to an SPI interface of an MCU -board (it needs to be reasonably fast). - -When sourcing ADXL345, be aware that there is a variety of different PCB -board designs and different clones of them. Make sure that the board supports -SPI mode (small number of boards appear to be hard-configured for I2C by -pulling SDO to GND), and, if it is going to be connected to a 5V printer MCU, -that it has a voltage regulator and a level shifter. - +Klipper has built-in support for the ADXL345 and MPU-9250 compatible +accelerometers which can be used to measure resonance frequencies of the printer +for different axes, and auto-tune [input shapers](Resonance_Compensation.md) to +compensate for resonances. Note that using accelerometers requires some +soldering and crimping. The ADXL345 can be connected to the SPI interface of a +Raspberry Pi or MCU board (it needs to be reasonably fast). The MPU family can +be connected to the I2C interface of a Raspberry Pi directly, or to an I2C +interface of an MCU board that supports 400kbit/s *fast mode* in Klipper. + +When sourcing accelerometers, be aware that there are a variety of different PCB +board designs and different clones of them. If it is going to be connected to a +5V printer MCU ensure it has a voltage regulator and level shifters. + +For ADXL345s, make sure that the board supports SPI mode (a small number of +boards appear to be hard-configured for I2C by pulling SDO to GND). + +For MPU-9250/MPU-9255/MPU-6515/MPU-6050/MPU-6500s there are also a variety of +board designs and clones with different I2C pull-up resistors which will need +supplementing. + +## MCUs with Klipper I2C *fast-mode* Support + +| MCU Family | MCU(s) Tested | MCU(s) with Support | +|:--:|:--|:--| +| Raspberry Pi | 3B+, Pico | 3A, 3A+, 3B, 4 | +| AVR ATmega | ATmega328p | ATmega32u4, ATmega128, ATmega168, ATmega328, ATmega644p, ATmega1280, ATmega1284, ATmega2560 | +| AVR AT90 | - | AT90usb646, AT90usb1286 | ## Installation instructions ### Wiring An ethernet cable with shielded twisted pairs (cat5e or better) is recommended -for signal integrity over a long distance. If you still experience signal integrity -issues (SPI/I2C errors), shorten the cable. - -Connect ethernet cable shielding to the controller board/RPI ground. +for signal integrity over a long distance. If you still experience signal +integrity issues (SPI/I2C errors): + +- Double check the wiring with a digital multimeter for: + - Correct connections when turned off (continuity) + - Correct power and ground voltages +- I2C only: + - Check the SCL and SDA lines' resistances to 3.3V are in the range of 900 + ohms to 1.8K + - For full technical details consult [chapter 7 of the I2C-bus specification + and user manual UM10204](https://www.pololu.com/file/0J435/UM10204.pdf) + for *fast-mode* +- Shorten the cable + +Connect ethernet cable shielding only to the MCU board/Pi ground. ***Double-check your wiring before powering up to prevent damaging your MCU/Raspberry Pi or the accelerometer.*** -#### SPI Accelerometers +### SPI Accelerometers -Suggested twisted pair order: +Suggested twisted pair order for three twisted pairs: ``` GND+MISO @@ -37,11 +62,15 @@ GND+MISO SCLK+CS ``` -##### ADXL345 +Note that unlike a cable shield, GND must be connected at both ends. +#### ADXL345 -**Note: Many MCUs will work with an ADXL345 in SPI mode(eg Pi Pico), wiring and -configuration will vary according to your specific board and available pins.** +##### Direct to Raspberry Pi + +**Note: Many MCUs will work with an ADXL345 in SPI mode (e.g. Pi Pico), wiring +and configuration will vary according to your specific board and available +pins.** You need to connect ADXL345 to your Raspberry Pi via SPI. Note that the I2C connection, which is suggested by ADXL345 documentation, has too low throughput @@ -60,20 +89,56 @@ Fritzing wiring diagrams for some of the ADXL345 boards: ![ADXL345-Rpi](img/adxl345-fritzing.png) -#### I2C Accelerometers +##### Using Raspberry Pi Pico + +You may connect the ADXL345 to your Raspberry Pi Pico and then connect the +Pico to your Raspberry Pi via USB. This makes it easy to reuse the +accelerometer on other Klipper devices, as you can connect via USB instead +of GPIO. The Pico does not have much processing power, so make sure it is +only running the accelerometer and not performing any other duties. + +In order to avoid damage to your RPi make sure to connect the ADXL345 to 3.3V +only. Depending on the board's layout, a level shifter may be present, which +makes 5V dangerous for your RPi. + +| ADXL345 pin | Pico pin | Pico pin name | +|:--:|:--:|:--:| +| 3V3 (or VCC) | 36 | 3.3V DC power | +| GND | 38 | Ground | +| CS | 2 | GP1 (SPI0_CSn) | +| SDO | 1 | GP0 (SPI0_RX) | +| SDA | 5 | GP3 (SPI0_TX) | +| SCL | 4 | GP2 (SPI0_SCK) | + +Wiring diagrams for some of the ADXL345 boards: -Suggested twisted pair order: +![ADXL345-Pico](img/adxl345-pico.png) + +### I2C Accelerometers + +Suggested twisted pair order for three pairs (preferred): + +``` +3.3V+GND +SDA+GND +SCL+GND +``` + +or for two pairs: ``` 3.3V+SDA GND+SCL ``` -##### MPU-9250/MPU-9255/MPU-6515/MPU-6050/MPU-6500 +Note that unlike a cable shield, any GND(s) should be connected at both ends. + +#### MPU-9250/MPU-9255/MPU-6515/MPU-6050/MPU-6500 -Alternatives to the ADXL345 are MPU-9250/MPU-9255/MPU-6515/MPU-6050/MPU-6500. -These accelerometers have been tested to work over I2C on the RPi or RP2040(pico) -at 400kbaud. +These accelerometers have been tested to work over I2C on the RPi, RP2040 (Pico) +and AVR at 400kbit/s (*fast mode*). Some MPU accelerometer modules include +pull-ups, but some are too large at 10K and must be changed or supplemented by +smaller parallel resistors. Recommended connection scheme for I2C on the Raspberry Pi: @@ -84,18 +149,34 @@ Recommended connection scheme for I2C on the Raspberry Pi: | SDA | 03 | GPIO02 (SDA1) | | SCL | 05 | GPIO03 (SCL1) | -![MPU-9250 connected to RPI](img/mpu9250-PI-fritzing.png) +The RPi has buit-in 1.8K pull-ups on both SCL and SDA. -Recommended connection scheme for I2C(i2c0a) on the RP2040: +![MPU-9250 connected to Pi](img/mpu9250-PI-fritzing.png) -| MPU-9250 pin | RP2040 pin | RPi pin name | +Recommended connection scheme for I2C (i2c0a) on the RP2040: + +| MPU-9250 pin | RP2040 pin | RP2040 pin name | |:--:|:--:|:--:| -| VCC | 39 | 3v3 | +| VCC | 36 | 3v3 | | GND | 38 | Ground | | SDA | 01 | GP0 (I2C0 SDA) | | SCL | 02 | GP1 (I2C0 SCL) | -![MPU-9250 connected to PICO](img/mpu9250-PICO-fritzing.png) +The Pico does not include any built-in I2C pull-up resistors. + +![MPU-9250 connected to Pico](img/mpu9250-PICO-fritzing.png) + +##### Recommended connection scheme for I2C(TWI) on the AVR ATmega328P Arduino Nano: + +| MPU-9250 pin | Atmega328P TQFP32 pin | Atmega328P pin name | Arduino Nano pin | +|:--:|:--:|:--:|:--:| +| VCC | 39 | - | - | +| GND | 38 | Ground | GND | +| SDA | 27 | SDA | A4 | +| SCL | 28 | SCL | A5 | + +The Arduino Nano does not include any built-in pull-up resistors nor a 3.3V +power pin. ### Mounting the accelerometer @@ -164,6 +245,65 @@ probe_points: It is advised to start with 1 probe point, in the middle of the print bed, slightly above it. +#### Configure ADXL345 With Pi Pico + +##### Flash the Pico Firmware + +On your Raspberry Pi, compile the firmware for the Pico. + +``` +cd ~/klipper +make clean +make menuconfig +``` +![Pico menuconfig](img/klipper_pico_menuconfig.png) + +Now, while holding down the `BOOTSEL` button on the Pico, connect the Pico to +the Raspberry Pi via USB. Compile and flash the firmware. +``` +make flash FLASH_DEVICE=first +``` + +If that fails, you will be told which `FLASH_DEVICE` to use. In this example, +that's ```make flash FLASH_DEVICE=2e8a:0003```. +![Determine flash device](img/flash_rp2040_FLASH_DEVICE.png) + +##### Configure the Connection + +The Pico will now reboot with the new firmware and should show up as a serial +device. Find the pico serial device with `ls /dev/serial/by-id/*`. You can +now add an `adxl.cfg` file with the following settings: + +``` +[mcu adxl] +# Change to whatever you found above. For example, +# usb-Klipper_rp2040_E661640843545B2E-if00 +serial: /dev/serial/by-id/usb-Klipper_rp2040_ + +[adxl345] +cs_pin: adxl:gpio1 +spi_bus: spi0a +axes_map: x,z,y + +[resonance_tester] +accel_chip: adxl345 +probe_points: + # Somewhere slightly above the middle of your print bed + 147,154, 20 + +[output_pin power_mode] # Improve power stability +pin: adxl:gpio23 +``` + +If setting up the ADXL345 configuration in a separate file, as shown above, +you'll also want to modify your `printer.cfg` file to include this: + +``` +[include adxl.cfg] # Comment this out when you disconnect the accelerometer +``` + +Restart Klipper via the `RESTART` command. + #### Configure MPU-6000/9000 series With RPi Make sure the Linux I2C driver is enabled and the baud rate is @@ -184,14 +324,14 @@ probe_points: 100, 100, 20 # an example ``` -#### Configure MPU-6000/9000 series With PICO +#### Configure MPU-9520 Compatibles With Pico -PICO I2C is set to 400000 on default. Simply add the following to the +Pico I2C is set to 400000 on default. Simply add the following to the printer.cfg: ``` [mcu pico] -serial: /dev/serial/by-id/ +serial: /dev/serial/by-id/ [mpu9250] i2c_mcu: pico @@ -203,7 +343,25 @@ probe_points: 100, 100, 20 # an example [static_digital_output pico_3V3pwm] # Improve power stability -pin: pico:gpio23 +pins: pico:gpio23 +``` + +#### Configure MPU-9520 Compatibles with AVR + +AVR I2C will be set to 400000 by the mpu9250 option. Simply add the following +to the printer.cfg: + +``` +[mcu nano] +serial: /dev/serial/by-id/ + +[mpu9250] +i2c_mcu: nano + +[resonance_tester] +accel_chip: mpu9250 +probe_points: + 100, 100, 20 # an example ``` Restart Klipper via the `RESTART` command. @@ -228,12 +386,14 @@ Recv: // adxl345 values (x, y, z): 470.719200, 941.438400, 9728.196800 ``` If you get an error like `Invalid adxl345 id (got xx vs e5)`, where `xx` -is some other ID, it is indicative of the connection problem with ADXL345, +is some other ID, immediately try again. There's an issue with SPI +initialization. If you still get an error, it is indicative of the connection +problem with ADXL345, or the faulty sensor. Double-check the power, the wiring (that it matches the schematics, no wire is broken or loose, etc.), and soldering quality. -**If you are using MPU-6000/9000 series accelerometer and it show up as `mpu-unknown`, use with -caution! They are probably refurbished chips!** +**If you are using a MPU-9250 compatible accelerometer and it shows up as +`mpu-unknown`, use with caution! They are probably refurbished chips!** Next, try running `MEASURE_AXES_NOISE` in Octoprint, you should get some baseline numbers for the noise of accelerometer on the axes (should be @@ -322,10 +482,11 @@ of the accelerometer between the measurements for X and Y axes: measure the resonances of X axis with the accelerometer attached to the toolhead and the resonances of Y axis - to the bed (the usual bed slinger setup). -However, you can also connect two accelerometers simultaneously, though they -must be connected to different boards (say, to an RPi and printer MCU board), or -to two different physical SPI interfaces on the same board (rarely available). -Then they can be configured in the following manner: +However, you can also connect two accelerometers simultaneously, though the +ADXL345 must be connected to different boards (say, to an RPi and printer MCU +board), or to two different physical SPI interfaces on the same board (rarely +available). Then they can be configured in the following manner: + ``` [adxl345 hotend] # Assuming `hotend` chip is connected to an RPi @@ -342,6 +503,30 @@ accel_chip_y: adxl345 bed probe_points: ... ``` +Two MPUs can share one I2C bus, but they **cannot** measure simultaneously as +the 400kbit/s I2C bus is not fast enough. One must have its AD0 pin pulled-down +to 0V (address 104) and the other its AD0 pin pulled-up to 3.3V (address 105): + +``` +[mpu9250 hotend] +i2c_mcu: rpi +i2c_bus: i2c.1 +i2c_address: 104 # This MPU has pin AD0 pulled low + +[mpu9250 bed] +i2c_mcu: rpi +i2c_bus: i2c.1 +i2c_address: 105 # This MPU has pin AD0 pulled high + +[resonance_tester] +# Assuming the typical setup of the bed slinger printer +accel_chip_x: mpu9250 hotend +accel_chip_y: mpu9250 bed +probe_points: ... +``` +[Test with each MPU individually before connecting both to the bus for easy +debugging.] + Then the commands `TEST_RESONANCES AXIS=X` and `TEST_RESONANCES AXIS=Y` will use the correct accelerometer for each axis. diff --git a/docs/Slicers.md b/docs/Slicers.md index cb0f5e6d06fb..afffe7499994 100644 --- a/docs/Slicers.md +++ b/docs/Slicers.md @@ -103,7 +103,9 @@ START_PRINT BED_TEMP={material_bed_temperature_layer_0} EXTRUDER_TEMP={material_ In slic3r derivatives such as PrusaSlicer and SuperSlicer, the following would be used: +``` START_PRINT EXTRUDER_TEMP=[first_layer_temperature] BED_TEMP=[first_layer_bed_temperature] +``` Also note that these slicers will insert their own heating codes when certain conditions are not met. In Cura, the existence of the diff --git a/docs/Status_Reference.md b/docs/Status_Reference.md index 423e3fd50a68..84b4de73ae00 100644 --- a/docs/Status_Reference.md +++ b/docs/Status_Reference.md @@ -458,6 +458,9 @@ objects (eg, `[tmc2208 stepper_x]`): - `drv_status`: The results of the last driver status query. (Only non-zero fields are reported.) This field will be null if the driver is not enabled (and thus is not periodically queried). +- `temperature`: The internal temperature reported by the driver. This + field will be null if the driver is not enabled or if the driver + does not support temperature reporting. - `run_current`: The currently set run current. - `hold_current`: The currently set hold current. diff --git a/docs/img/adxl345-pico.png b/docs/img/adxl345-pico.png new file mode 100644 index 000000000000..77bce31baebb Binary files /dev/null and b/docs/img/adxl345-pico.png differ diff --git a/docs/img/flash_rp2040_FLASH_DEVICE.png b/docs/img/flash_rp2040_FLASH_DEVICE.png new file mode 100644 index 000000000000..7687811e4514 Binary files /dev/null and b/docs/img/flash_rp2040_FLASH_DEVICE.png differ diff --git a/docs/img/klipper_pico_menuconfig.png b/docs/img/klipper_pico_menuconfig.png new file mode 100644 index 000000000000..478ee4a15437 Binary files /dev/null and b/docs/img/klipper_pico_menuconfig.png differ diff --git a/klippy/chelper/serialqueue.c b/klippy/chelper/serialqueue.c index 684710c1d8cd..b6500fe621d5 100644 --- a/klippy/chelper/serialqueue.c +++ b/klippy/chelper/serialqueue.c @@ -30,7 +30,7 @@ #include "serialqueue.h" // struct queue_message struct command_queue { - struct list_head stalled_queue, ready_queue; + struct list_head upcoming_queue, ready_queue; struct list_node node; }; @@ -59,7 +59,7 @@ struct serialqueue { double srtt, rttvar, rto; // Pending transmission message queues struct list_head pending_queues; - int ready_bytes, stalled_bytes, need_ack_bytes, last_ack_bytes; + int ready_bytes, upcoming_bytes, need_ack_bytes, last_ack_bytes; uint64_t need_kick_clock; struct list_head notify_queue; // Received messages @@ -458,7 +458,7 @@ build_and_send_command(struct serialqueue *sq, uint8_t *buf, int pending if (len + qm->len > MESSAGE_MAX - MESSAGE_TRAILER_SIZE) break; list_del(&qm->node); - if (list_empty(&cq->ready_queue) && list_empty(&cq->stalled_queue)) + if (list_empty(&cq->ready_queue) && list_empty(&cq->upcoming_queue)) list_del(&cq->node); memcpy(&buf[len], qm->msg, qm->len); len += qm->len; @@ -523,10 +523,10 @@ check_send_command(struct serialqueue *sq, int pending, double eventtime) uint64_t min_stalled_clock = MAX_CLOCK, min_ready_clock = MAX_CLOCK; struct command_queue *cq; list_for_each_entry(cq, &sq->pending_queues, node) { - // Move messages from the stalled_queue to the ready_queue - while (!list_empty(&cq->stalled_queue)) { + // Move messages from the upcoming_queue to the ready_queue + while (!list_empty(&cq->upcoming_queue)) { struct queue_message *qm = list_first_entry( - &cq->stalled_queue, struct queue_message, node); + &cq->upcoming_queue, struct queue_message, node); if (ack_clock < qm->min_clock) { if (qm->min_clock < min_stalled_clock) min_stalled_clock = qm->min_clock; @@ -534,7 +534,7 @@ check_send_command(struct serialqueue *sq, int pending, double eventtime) } list_del(&qm->node); list_add_tail(&qm->node, &cq->ready_queue); - sq->stalled_bytes -= qm->len; + sq->upcoming_bytes -= qm->len; sq->ready_bytes += qm->len; } // Update min_ready_clock @@ -714,7 +714,7 @@ serialqueue_free(struct serialqueue *sq) &sq->pending_queues, struct command_queue, node); list_del(&cq->node); message_queue_free(&cq->ready_queue); - message_queue_free(&cq->stalled_queue); + message_queue_free(&cq->upcoming_queue); } pthread_mutex_unlock(&sq->lock); pollreactor_free(sq->pr); @@ -728,7 +728,7 @@ serialqueue_alloc_commandqueue(void) struct command_queue *cq = malloc(sizeof(*cq)); memset(cq, 0, sizeof(*cq)); list_init(&cq->ready_queue); - list_init(&cq->stalled_queue); + list_init(&cq->upcoming_queue); return cq; } @@ -738,7 +738,7 @@ serialqueue_free_commandqueue(struct command_queue *cq) { if (!cq) return; - if (!list_empty(&cq->ready_queue) || !list_empty(&cq->stalled_queue)) { + if (!list_empty(&cq->ready_queue) || !list_empty(&cq->upcoming_queue)) { errorf("Memory leak! Can't free non-empty commandqueue"); return; } @@ -784,12 +784,12 @@ serialqueue_send_batch(struct serialqueue *sq, struct command_queue *cq return; qm = list_first_entry(msgs, struct queue_message, node); - // Add list to cq->stalled_queue + // Add list to cq->upcoming_queue pthread_mutex_lock(&sq->lock); - if (list_empty(&cq->ready_queue) && list_empty(&cq->stalled_queue)) + if (list_empty(&cq->ready_queue) && list_empty(&cq->upcoming_queue)) list_add_tail(&cq->node, &sq->pending_queues); - list_join_tail(msgs, &cq->stalled_queue); - sq->stalled_bytes += len; + list_join_tail(msgs, &cq->upcoming_queue); + sq->upcoming_bytes += len; int mustwake = 0; if (qm->min_clock < sq->need_kick_clock) { sq->need_kick_clock = 0; @@ -925,13 +925,13 @@ serialqueue_get_stats(struct serialqueue *sq, char *buf, int len) " bytes_retransmit=%u bytes_invalid=%u" " send_seq=%u receive_seq=%u retransmit_seq=%u" " srtt=%.3f rttvar=%.3f rto=%.3f" - " ready_bytes=%u stalled_bytes=%u" + " ready_bytes=%u upcoming_bytes=%u" , stats.bytes_write, stats.bytes_read , stats.bytes_retransmit, stats.bytes_invalid , (int)stats.send_seq, (int)stats.receive_seq , (int)stats.retransmit_seq , stats.srtt, stats.rttvar, stats.rto - , stats.ready_bytes, stats.stalled_bytes); + , stats.ready_bytes, stats.upcoming_bytes); } // Extract old messages stored in the debug queues diff --git a/klippy/extras/aht10.py b/klippy/extras/aht10.py new file mode 100644 index 000000000000..001f7e54d59a --- /dev/null +++ b/klippy/extras/aht10.py @@ -0,0 +1,162 @@ +# AHT10/AHT20/AHT21 I2c-based humiditure sensor support +# +# Copyright (C) 2023 Scott Mudge +# +# This file may be distributed under the terms of the GNU GPLv3 license. +import logging +from . import bus + +###################################################################### +# Compatible Sensors: +# AHT10 - Tested w/ BTT GTR 1.0 MCU on i2c3 +# AHT20 - Untested but should work +# AHT21 - Tested w/ BTT GTR 1.0 MCU on i2c3 +###################################################################### + +AHT10_I2C_ADDR= 0x38 + +AHT10_COMMANDS = { + 'INIT' :[0xE1, 0x08, 0x00], + 'MEASURE' :[0xAC, 0x33, 0x00], + 'RESET' :[0xBA, 0x08, 0x00] +} + +AHT10_MAX_BUSY_CYCLES= 5 + +class AHT10: + def __init__(self, config): + self.printer = config.get_printer() + self.name = config.get_name().split()[-1] + self.reactor = self.printer.get_reactor() + self.i2c = bus.MCU_I2C_from_config( + config, default_addr=AHT10_I2C_ADDR, default_speed=100000) + self.report_time = config.getint('aht10_report_time',30,minval=5) + self.temp = self.min_temp = self.max_temp = self.humidity = 0. + self.sample_timer = self.reactor.register_timer(self._sample_aht10) + self.printer.add_object("aht10 " + self.name, self) + self.printer.register_event_handler("klippy:connect", + self.handle_connect) + self.is_calibrated = False + self.init_sent = False + + def handle_connect(self): + self._init_aht10() + self.reactor.update_timer(self.sample_timer, self.reactor.NOW) + + def setup_minmax(self, min_temp, max_temp): + self.min_temp = min_temp + self.max_temp = max_temp + + def setup_callback(self, cb): + self._callback = cb + + def get_report_time_delta(self): + return self.report_time + + def _make_measurement(self): + if not self.init_sent: + return False + + data = None + + is_busy = True + cycles = 0 + + try: + while is_busy: + # Check if we're constantly busy. If so, send soft-reset + # and issue warning. + if is_busy and cycles > AHT10_MAX_BUSY_CYCLES: + logging.warning("aht10: device reported busy after " + + "%d cycles, resetting device"% AHT10_MAX_BUSY_CYCLES) + self._reset_device() + data = None + break + + cycles += 1 + # Write command for updating temperature+status bit + self.i2c.i2c_write(AHT10_COMMANDS['MEASURE']) + # Wait 110ms after first read, 75ms minimum + self.reactor.pause(self.reactor.monotonic() + .110) + + # Read data + read = self.i2c.i2c_read([], 6) + if read is None: + logging.warning("aht10: received data from" + + " i2c_read is None") + continue + data = bytearray(read['response']) + if len(data) < 6: + logging.warning("aht10: received bytes less than" + + " expected 6 [%d]"%len(data)) + continue + + self.is_calibrated = True if (data[0] & 0b00000100) else False + is_busy = True if (data[0] & 0b01000000) else False + + if is_busy: + return False + except Exception as e: + logging.exception("aht10: exception encountered" + + " reading data: %s"%str(e)) + return False + + temp = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5] + self.temp = ((temp*200) / 1048576) - 50 + hum = ((data[1] << 16) | (data[2] << 8) | data[3]) >> 4 + self.humidity = int(hum * 100 / 1048576) + + # Clamp humidity + if (self.humidity > 100): + self.humidity = 100 + elif (self.humidity < 0): + self.humidity = 0 + + return True + + def _reset_device(self): + if not self.init_sent: + return + + # Reset device + self.i2c.i2c_write(AHT10_COMMANDS['RESET']) + # Wait 100ms after reset + self.reactor.pause(self.reactor.monotonic() + .10) + + def _init_aht10(self): + # Init device + self.i2c.i2c_write(AHT10_COMMANDS['INIT']) + # Wait 100ms after init + self.reactor.pause(self.reactor.monotonic() + .10) + self.init_sent = True + + if self._make_measurement(): + logging.info("aht10: successfully initialized, initial temp: " + + "%.3f, humidity: %.3f"%(self.temp, self.humidity)) + + def _sample_aht10(self, eventtime): + if not self._make_measurement(): + self.temp = self.humidity = .0 + return self.reactor.NEVER + + if self.temp < self.min_temp or self.temp > self.max_temp: + self.printer.invoke_shutdown( + "AHT10 temperature %0.1f outside range of %0.1f:%.01f" + % (self.temp, self.min_temp, self.max_temp)) + + measured_time = self.reactor.monotonic() + print_time = self.i2c.get_mcu().estimated_print_time(measured_time) + self._callback(print_time, self.temp) + return measured_time + self.report_time + + def get_status(self, eventtime): + return { + 'temperature': round(self.temp, 2), + 'humidity': self.humidity, + } + + +def load_config(config): + # Register sensor + pheater = config.get_printer().lookup_object("heaters") + pheater.add_sensor_factory("AHT10", AHT10) diff --git a/klippy/extras/gcode_macro.py b/klippy/extras/gcode_macro.py index 4f50c75ade02..78cdae0eea3c 100644 --- a/klippy/extras/gcode_macro.py +++ b/klippy/extras/gcode_macro.py @@ -3,7 +3,7 @@ # Copyright (C) 2018-2021 Kevin O'Connor # # This file may be distributed under the terms of the GNU GPLv3 license. -import traceback, logging, ast, copy +import traceback, logging, ast, copy, json import jinja2 @@ -144,12 +144,13 @@ def __init__(self, config): prefix = 'variable_' for option in config.get_prefix_options(prefix): try: - self.variables[option[len(prefix):]] = ast.literal_eval( - config.get(option)) - except ValueError as e: + literal = ast.literal_eval(config.get(option)) + json.dumps(literal, separators=(',', ':')) + self.variables[option[len(prefix):]] = literal + except (SyntaxError, TypeError, ValueError) as e: raise config.error( - "Option '%s' in section '%s' is not a valid literal" % ( - option, config.get_name())) + "Option '%s' in section '%s' is not a valid literal: %s" % ( + option, config.get_name(), e)) def handle_connect(self): prev_cmd = self.gcode.register_command(self.alias, None) if prev_cmd is None: @@ -169,8 +170,10 @@ def cmd_SET_GCODE_VARIABLE(self, gcmd): raise gcmd.error("Unknown gcode_macro variable '%s'" % (variable,)) try: literal = ast.literal_eval(value) - except ValueError as e: - raise gcmd.error("Unable to parse '%s' as a literal" % (value,)) + json.dumps(literal, separators=(',', ':')) + except (SyntaxError, TypeError, ValueError) as e: + raise gcmd.error("Unable to parse '%s' as a literal: %s" % + (value, e)) v = dict(self.variables) v[variable] = literal self.variables = v diff --git a/klippy/extras/mpu9250.py b/klippy/extras/mpu9250.py index 419207fc4384..dc25449bba7b 100644 --- a/klippy/extras/mpu9250.py +++ b/klippy/extras/mpu9250.py @@ -221,7 +221,7 @@ def _start_measurements(self): systime = self.printer.get_reactor().monotonic() print_time = self.mcu.estimated_print_time(systime) + MIN_MSG_TIME reqclock = self.mcu.print_time_to_clock(print_time) - rest_ticks = self.mcu.seconds_to_clock(1. / self.data_rate) + rest_ticks = self.mcu.seconds_to_clock(4. / self.data_rate) self.query_rate = self.data_rate self.query_mpu9250_cmd.send([self.oid, reqclock, rest_ticks], reqclock=reqclock) diff --git a/klippy/extras/temperature_sensors.cfg b/klippy/extras/temperature_sensors.cfg index ebee3089979d..7e0d918f5b8a 100644 --- a/klippy/extras/temperature_sensors.cfg +++ b/klippy/extras/temperature_sensors.cfg @@ -18,6 +18,9 @@ # Load "SI7013", "SI7020", "SI7021", "SHT21", and "HTU21D" sensors [htu21d] +# Load "AHT10" +[aht10] + # Load "LM75" sensor [lm75] diff --git a/klippy/extras/tmc.py b/klippy/extras/tmc.py index 36c27d5ce9ed..28f7be6fc01f 100644 --- a/klippy/extras/tmc.py +++ b/klippy/extras/tmc.py @@ -93,7 +93,7 @@ def __init__(self, config, mcu_tmc): self.mcu_tmc = mcu_tmc self.fields = mcu_tmc.get_fields() self.check_timer = None - self.last_drv_status = self.last_status = None + self.last_drv_status = self.last_drv_fields = None # Setup for GSTAT query reg_name = self.fields.lookup_register("drv_err") if reg_name is not None: @@ -122,6 +122,9 @@ def __init__(self, config, mcu_tmc): if f in err_fields: err_mask |= self.fields.all_fields[reg_name][f] self.drv_status_reg_info = [0, reg_name, mask, err_mask, cs_actual_mask] + # Setup for temperature query + self.adc_temp = None + self.adc_temp_reg = self.fields.lookup_register("adc_temp") def _query_register(self, reg_info, try_clear=False): last_value, reg_name, mask, err_mask, cs_actual_mask = reg_info cleared_flags = 0 @@ -161,11 +164,20 @@ def _query_register(self, reg_info, try_clear=False): cleared_flags |= val & err_mask self.mcu_tmc.set_register(reg_name, val & err_mask) return cleared_flags + def _query_temperature(self): + try: + self.adc_temp = self.mcu_tmc.get_register(self.adc_temp_reg) + except self.printer.command_error as e: + # Ignore comms error for temperature + self.adc_temp = None + return def _do_periodic_check(self, eventtime): try: self._query_register(self.drv_status_reg_info) if self.gstat_reg_info is not None: self._query_register(self.gstat_reg_info) + if self.adc_temp_reg is not None: + self._query_temperature() except self.printer.command_error as e: self.printer.invoke_shutdown(str(e)) return self.printer.get_reactor().NEVER @@ -194,14 +206,16 @@ def start_checks(self): return False def get_status(self, eventtime=None): if self.check_timer is None: - return {'drv_status': None} + return {'drv_status': None, 'temperature': None} + temp = None + if self.adc_temp is not None: + temp = round((self.adc_temp - 2038) / 7.7, 2) last_value, reg_name = self.drv_status_reg_info[:2] if last_value != self.last_drv_status: self.last_drv_status = last_value fields = self.fields.get_reg_fields(reg_name, last_value) - fields = {n: v for n, v in fields.items() if v} - self.last_status = {'drv_status': fields} - return self.last_status + self.last_drv_fields = {n: v for n, v in fields.items() if v} + return {'drv_status': self.last_drv_fields, 'temperature': temp} ###################################################################### @@ -413,17 +427,32 @@ def setup_register_dump(self, read_registers, read_translate=None): cmd_DUMP_TMC_help = "Read and display TMC stepper driver registers" def cmd_DUMP_TMC(self, gcmd): logging.info("DUMP_TMC %s", self.name) - print_time = self.printer.lookup_object('toolhead').get_last_move_time() - gcmd.respond_info("========== Write-only registers ==========") - for reg_name, val in self.fields.registers.items(): - if reg_name not in self.read_registers: + reg_name = gcmd.get('REGISTER', None) + if reg_name is not None: + reg_name = reg_name.upper() + val = self.fields.registers.get(reg_name) + if (val is not None) and (reg_name not in self.read_registers): + # write-only register + gcmd.respond_info(self.fields.pretty_format(reg_name, val)) + elif reg_name in self.read_registers: + # readable register + val = self.mcu_tmc.get_register(reg_name) + if self.read_translate is not None: + reg_name, val = self.read_translate(reg_name, val) + gcmd.respond_info(self.fields.pretty_format(reg_name, val)) + else: + raise gcmd.error("Unknown register name '%s'" % (reg_name)) + else: + gcmd.respond_info("========== Write-only registers ==========") + for reg_name, val in self.fields.registers.items(): + if reg_name not in self.read_registers: + gcmd.respond_info(self.fields.pretty_format(reg_name, val)) + gcmd.respond_info("========== Queried registers ==========") + for reg_name in self.read_registers: + val = self.mcu_tmc.get_register(reg_name) + if self.read_translate is not None: + reg_name, val = self.read_translate(reg_name, val) gcmd.respond_info(self.fields.pretty_format(reg_name, val)) - gcmd.respond_info("========== Queried registers ==========") - for reg_name in self.read_registers: - val = self.mcu_tmc.get_register(reg_name) - if self.read_translate is not None: - reg_name, val = self.read_translate(reg_name, val) - gcmd.respond_info(self.fields.pretty_format(reg_name, val)) ###################################################################### diff --git a/klippy/extras/tmc2240.py b/klippy/extras/tmc2240.py index 1bc4c1ca8a3a..45482509915a 100644 --- a/klippy/extras/tmc2240.py +++ b/klippy/extras/tmc2240.py @@ -394,6 +394,8 @@ def __init__(self, config): set_config_field(config, "pwm_lim", 12) # TPOWERDOWN set_config_field(config, "tpowerdown", 10) + # SG4_THRS + set_config_field(config, "sg4_angle_offset", 1) def load_config_prefix(config): return TMC2240(config) diff --git a/klippy/extras/tmc5160.py b/klippy/extras/tmc5160.py index 0e7acf60a60e..1e8266b3cf54 100644 --- a/klippy/extras/tmc5160.py +++ b/klippy/extras/tmc5160.py @@ -105,6 +105,13 @@ "diss2g": 0x01 << 30, "diss2vs": 0x01 << 31 } +Fields["DRV_CONF"] = { + "bbmtime": 0x1F << 0, + "bbmclks": 0x0F << 8, + "otselect": 0x03 << 16, + "drvstrength": 0x03 << 18, + "filt_isense": 0x03 << 20, +} Fields["DRV_STATUS"] = { "sg_result": 0x3FF << 0, "s2vsa": 0x01 << 12, @@ -352,6 +359,11 @@ def __init__(self, config): set_config_field(config, "seimin", 0) set_config_field(config, "sgt", 0) set_config_field(config, "sfilt", 0) + # DRV_CONF + set_config_field(config, "drvstrength", 0) + set_config_field(config, "bbmclks", 4) + set_config_field(config, "bbmtime", 0) + set_config_field(config, "filt_isense", 0) # IHOLDIRUN set_config_field(config, "iholddelay", 6) # PWMCONF diff --git a/klippy/webhooks.py b/klippy/webhooks.py index 43ff9a914e62..9188a4f70af4 100644 --- a/klippy/webhooks.py +++ b/klippy/webhooks.py @@ -268,8 +268,14 @@ def _process_request(self, web_request): self.send(result) def send(self, data): - jmsg = json.dumps(data, separators=(',', ':')) - self.send_buffer += jmsg.encode() + b"\x03" + try: + jmsg = json.dumps(data, separators=(',', ':')) + self.send_buffer += jmsg.encode() + b"\x03" + except (TypeError, ValueError) as e: + msg = ("json encoding error: %s" % (str(e),)) + logging.exception(msg) + self.printer.invoke_shutdown(msg) + return if not self.is_blocking: self._do_send() diff --git a/lib/README b/lib/README index 848cd03999c9..ce24bce650ca 100644 --- a/lib/README +++ b/lib/README @@ -155,8 +155,12 @@ used to upload firmware to devices flashed with the CanBoot bootloader. The can2040 directory contains code from: https://github.com/KevinOConnor/can2040 -revision 177b0073fe6f19281ee7f7fdbe9599e32d1b4b8b. +revision d1190afcaa6245c20da28199d06e453d2e743099. The Huada HC32F460 directory contains code from: https://www.hdsc.com.cn/Category83-1490 version 2.2 DDL minus example directory, empty/extra files + +The n32g45x directory contains parts of code from: + https://github.com/RT-Thread/rt-thread/tree/master/bsp/n32g452xx/Libraries/N32_Std_Driver +version v1.0.1 (77638c17877c4b6b0b81e189a36bb08b3384923b) diff --git a/lib/can2040/can2040.c b/lib/can2040/can2040.c index fb9e3fb62b64..759f09747ab9 100644 --- a/lib/can2040/can2040.c +++ b/lib/can2040/can2040.c @@ -267,7 +267,7 @@ pio_tx_send(struct can2040 *cd, uint32_t *data, uint32_t count) pio_hw_t *pio_hw = cd->pio_hw; pio_tx_reset(cd); pio_hw->instr_mem[can2040_offset_tx_got_recessive] = 0xa242; // nop [2] - int i; + uint32_t i; for (i=0; itxf[3] = data[i]; struct pio_sm_hw *sm = &pio_hw->sm[3]; @@ -351,7 +351,7 @@ pio_sm_setup(struct can2040 *cd) pio_signal_set_txpending(cd); // Load pio program - int i; + uint32_t i; for (i=0; iinstr_mem[i] = can2040_program_instructions[i]; @@ -436,9 +436,9 @@ static inline uint32_t crc_bytes(uint32_t crc, uint32_t data, uint32_t num) { switch (num) { - default: crc = crc_byte(crc, data >> 24); - case 3: crc = crc_byte(crc, data >> 16); - case 2: crc = crc_byte(crc, data >> 8); + default: crc = crc_byte(crc, data >> 24); /* FALLTHRU */ + case 3: crc = crc_byte(crc, data >> 16); /* FALLTHRU */ + case 2: crc = crc_byte(crc, data >> 8); /* FALLTHRU */ case 1: crc = crc_byte(crc, data); } return crc; @@ -647,14 +647,19 @@ tx_schedule_transmit(struct can2040 *cd) if (cd->tx_state == TS_QUEUED && !pio_tx_did_fail(cd)) // Already queued or actively transmitting return 0; - if (cd->tx_push_pos == cd->tx_pull_pos) { + uint32_t tx_pull_pos = cd->tx_pull_pos; + if (readl(&cd->tx_push_pos) == tx_pull_pos) { // No new messages to transmit cd->tx_state = TS_IDLE; pio_signal_clear_txpending(cd); - return SI_TXPENDING; + __DMB(); + if (likely(readl(&cd->tx_push_pos) == tx_pull_pos)) + return SI_TXPENDING; + // Raced with can2040_transmit() - msg is now available for transmit + pio_signal_set_txpending(cd); } cd->tx_state = TS_QUEUED; - struct can2040_transmit *qt = &cd->tx_queue[tx_qpos(cd, cd->tx_pull_pos)]; + struct can2040_transmit *qt = &cd->tx_queue[tx_qpos(cd, tx_pull_pos)]; pio_tx_send(cd, qt->stuffed_data, qt->stuffed_words); return 0; } @@ -717,7 +722,7 @@ report_callback_rx_msg(struct can2040 *cd) static void report_callback_tx_msg(struct can2040 *cd) { - cd->tx_pull_pos++; + writel(&cd->tx_pull_pos, cd->tx_pull_pos + 1); cd->rx_cb(cd, CAN2040_NOTIFY_TX, &cd->parse_msg); } @@ -856,7 +861,9 @@ report_line_maytx(struct can2040 *cd) static void report_line_txpending(struct can2040 *cd) { - if (cd->report_state == RS_NEED_RX_ACK) { + uint32_t pio_irqs = pio_irq_get(cd); + if (pio_irqs == (SI_MAYTX | SI_TXPENDING | SI_RX_DATA) + && cd->report_state == RS_NEED_RX_ACK) { // Ack inject request from report_note_crc_start() uint32_t mk = pio_match_calc_key(cd->parse_crc_bits, cd->parse_crc_pos); tx_inject_ack(cd, mk); @@ -866,7 +873,7 @@ report_line_txpending(struct can2040 *cd) // Tx request from can2040_transmit(), report_note_eof_success(), // or report_note_parse_error(). uint32_t check_txpending = tx_schedule_transmit(cd); - pio_irq_set(cd, (pio_irq_get(cd) & ~SI_TXPENDING) | check_txpending); + pio_irq_set(cd, (pio_irqs & ~SI_TXPENDING) | check_txpending); } @@ -1241,7 +1248,7 @@ can2040_transmit(struct can2040 *cd, struct can2040_msg *msg) crc = crc_bytes(crc, hdr, 3); bs_push(&bs, hdr, 19); } - int i; + uint32_t i; for (i=0; imsg.data[i]; crc = crc_byte(crc, v); @@ -1256,6 +1263,7 @@ can2040_transmit(struct can2040 *cd, struct can2040_msg *msg) writel(&cd->tx_push_pos, tx_push_pos + 1); // Wakeup if in TS_IDLE state + __DMB(); pio_signal_set_txpending(cd); return 0; diff --git a/lib/n32g45x/include/n32g45x_adc.h b/lib/n32g45x/include/n32g45x_adc.h new file mode 100644 index 000000000000..ab929feb83bb --- /dev/null +++ b/lib/n32g45x/include/n32g45x_adc.h @@ -0,0 +1,331 @@ +/***************************************************************************** + * Copyright (c) 2019, Nations Technologies Inc. + * + * All rights reserved. + * **************************************************************************** + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Nations' name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ****************************************************************************/ + +#ifndef ____N32G45x_ADC____ +#define ____N32G45x_ADC____ + +#define __IO volatile + +typedef struct +{ + uint32_t WorkMode; + uint32_t MultiChEn; + uint32_t ContinueConvEn; + uint32_t ExtTrigSelect; + uint32_t DatAlign; + uint8_t ChsNumber; +} ADC_InitType; + +typedef struct +{ + __IO uint32_t STS; + __IO uint32_t CTRL1; + __IO uint32_t CTRL2; + __IO uint32_t SAMPT1; + __IO uint32_t SAMPT2; + __IO uint32_t JOFFSET1; + __IO uint32_t JOFFSET2; + __IO uint32_t JOFFSET3; + __IO uint32_t JOFFSET4; + __IO uint32_t WDGHIGH; + __IO uint32_t WDGLOW; + __IO uint32_t RSEQ1; + __IO uint32_t RSEQ2; + __IO uint32_t RSEQ3; + __IO uint32_t JSEQ; + __IO uint32_t JDAT1; + __IO uint32_t JDAT2; + __IO uint32_t JDAT3; + __IO uint32_t JDAT4; + __IO uint32_t DAT; + __IO uint32_t DIFSEL; + __IO uint32_t CALFACT; + __IO uint32_t CTRL3; + __IO uint32_t SAMPT3; +} ADC_Module; + +#define NS_ADC1_BASE ((uint32_t)0x40020800) +#define NS_ADC2_BASE ((uint32_t)0x40020c00) +#define NS_ADC3_BASE ((uint32_t)0x40021800) +#define NS_ADC4_BASE ((uint32_t)0x40021c00) + +#define NS_ADC1 ((ADC_Module *)NS_ADC1_BASE) +#define NS_ADC2 ((ADC_Module *)NS_ADC2_BASE) +#define NS_ADC3 ((ADC_Module *)NS_ADC3_BASE) +#define NS_ADC4 ((ADC_Module *)NS_ADC4_BASE) + +#define ADC_RCC_BASE ((uint32_t)0x40021000) +#define ADC_RCC_CTRL *((uint32_t *)(ADC_RCC_BASE + 0x00)) +#define ADC_RCC_CFG *((uint32_t *)(ADC_RCC_BASE + 0x04)) +#define ADC_RCC_CLKINT *((uint32_t *)(ADC_RCC_BASE + 0x08)) +#define ADC_RCC_APB2PRST *((uint32_t *)(ADC_RCC_BASE + 0x0c)) +#define ADC_RCC_APB1PRST *((uint32_t *)(ADC_RCC_BASE + 0x10)) +#define ADC_RCC_AHBPCLKEN *((uint32_t *)(ADC_RCC_BASE + 0x14)) +#define ADC_RCC_APB2PCLKEN *((uint32_t *)(ADC_RCC_BASE + 0x18)) +#define ADC_RCC_APB1PCLKEN *((uint32_t *)(ADC_RCC_BASE + 0x1c)) +#define ADC_RCC_BDCTRL *((uint32_t *)(ADC_RCC_BASE + 0x20)) +#define ADC_RCC_CTRLSTS *((uint32_t *)(ADC_RCC_BASE + 0x24)) +#define ADC_RCC_AHBPRST *((uint32_t *)(ADC_RCC_BASE + 0x28)) +#define ADC_RCC_CFG2 *((uint32_t *)(ADC_RCC_BASE + 0x2c)) +#define ADC_RCC_CFG3 *((uint32_t *)(ADC_RCC_BASE + 0x30)) + +/* CFG2 register bit mask */ +#define CFG2_TIM18CLKSEL_SET_MASK ((uint32_t)0x20000000) +#define CFG2_TIM18CLKSEL_RESET_MASK ((uint32_t)0xDFFFFFFF) +#define CFG2_RNGCPRES_SET_MASK ((uint32_t)0x1F000000) +#define CFG2_RNGCPRES_RESET_MASK ((uint32_t)0xE0FFFFFF) +#define CFG2_ADC1MSEL_SET_MASK ((uint32_t)0x00000400) +#define CFG2_ADC1MSEL_RESET_MASK ((uint32_t)0xFFFFFBFF) +#define CFG2_ADC1MPRES_SET_MASK ((uint32_t)0x0000F800) +#define CFG2_ADC1MPRES_RESET_MASK ((uint32_t)0xFFFF07FF) +#define CFG2_ADCPLLPRES_SET_MASK ((uint32_t)0x000001F0) +#define CFG2_ADCPLLPRES_RESET_MASK ((uint32_t)0xFFFFFE0F) +#define CFG2_ADCHPRES_SET_MASK ((uint32_t)0x0000000F) +#define CFG2_ADCHPRES_RESET_MASK ((uint32_t)0xFFFFFFF0) + +#define RCC_ADCPLLCLK_DISABLE ((uint32_t)0xFFFFFEFF) +#define RCC_ADCPLLCLK_DIV1 ((uint32_t)0x00000100) +#define RCC_ADCPLLCLK_DIV2 ((uint32_t)0x00000110) +#define RCC_ADCPLLCLK_DIV4 ((uint32_t)0x00000120) +#define RCC_ADCPLLCLK_DIV6 ((uint32_t)0x00000130) +#define RCC_ADCPLLCLK_DIV8 ((uint32_t)0x00000140) +#define RCC_ADCPLLCLK_DIV10 ((uint32_t)0x00000150) +#define RCC_ADCPLLCLK_DIV12 ((uint32_t)0x00000160) +#define RCC_ADCPLLCLK_DIV16 ((uint32_t)0x00000170) +#define RCC_ADCPLLCLK_DIV32 ((uint32_t)0x00000180) +#define RCC_ADCPLLCLK_DIV64 ((uint32_t)0x00000190) +#define RCC_ADCPLLCLK_DIV128 ((uint32_t)0x000001A0) +#define RCC_ADCPLLCLK_DIV256 ((uint32_t)0x000001B0) +#define RCC_ADCPLLCLK_DIV_OTHERS ((uint32_t)0x000001C0) + +#define RCC_ADCHCLK_DIV1 ((uint32_t)0x00000000) +#define RCC_ADCHCLK_DIV2 ((uint32_t)0x00000001) +#define RCC_ADCHCLK_DIV4 ((uint32_t)0x00000002) +#define RCC_ADCHCLK_DIV6 ((uint32_t)0x00000003) +#define RCC_ADCHCLK_DIV8 ((uint32_t)0x00000004) +#define RCC_ADCHCLK_DIV10 ((uint32_t)0x00000005) +#define RCC_ADCHCLK_DIV12 ((uint32_t)0x00000006) +#define RCC_ADCHCLK_DIV16 ((uint32_t)0x00000007) +#define RCC_ADCHCLK_DIV32 ((uint32_t)0x00000008) +#define RCC_ADCHCLK_DIV_OTHERS ((uint32_t)0x00000008) + +#define RCC_ADC1MCLK_SRC_HSI ((uint32_t)0x00000000) +#define RCC_ADC1MCLK_SRC_HSE ((uint32_t)0x00000400) + +#define RCC_ADC1MCLK_DIV1 ((uint32_t)0x00000000) +#define RCC_ADC1MCLK_DIV2 ((uint32_t)0x00000800) +#define RCC_ADC1MCLK_DIV3 ((uint32_t)0x00001000) +#define RCC_ADC1MCLK_DIV4 ((uint32_t)0x00001800) +#define RCC_ADC1MCLK_DIV5 ((uint32_t)0x00002000) +#define RCC_ADC1MCLK_DIV6 ((uint32_t)0x00002800) +#define RCC_ADC1MCLK_DIV7 ((uint32_t)0x00003000) +#define RCC_ADC1MCLK_DIV8 ((uint32_t)0x00003800) +#define RCC_ADC1MCLK_DIV9 ((uint32_t)0x00004000) +#define RCC_ADC1MCLK_DIV10 ((uint32_t)0x00004800) +#define RCC_ADC1MCLK_DIV11 ((uint32_t)0x00005000) +#define RCC_ADC1MCLK_DIV12 ((uint32_t)0x00005800) +#define RCC_ADC1MCLK_DIV13 ((uint32_t)0x00006000) +#define RCC_ADC1MCLK_DIV14 ((uint32_t)0x00006800) +#define RCC_ADC1MCLK_DIV15 ((uint32_t)0x00007000) +#define RCC_ADC1MCLK_DIV16 ((uint32_t)0x00007800) +#define RCC_ADC1MCLK_DIV17 ((uint32_t)0x00008000) +#define RCC_ADC1MCLK_DIV18 ((uint32_t)0x00008800) +#define RCC_ADC1MCLK_DIV19 ((uint32_t)0x00009000) +#define RCC_ADC1MCLK_DIV20 ((uint32_t)0x00009800) +#define RCC_ADC1MCLK_DIV21 ((uint32_t)0x0000A000) +#define RCC_ADC1MCLK_DIV22 ((uint32_t)0x0000A800) +#define RCC_ADC1MCLK_DIV23 ((uint32_t)0x0000B000) +#define RCC_ADC1MCLK_DIV24 ((uint32_t)0x0000B800) +#define RCC_ADC1MCLK_DIV25 ((uint32_t)0x0000C000) +#define RCC_ADC1MCLK_DIV26 ((uint32_t)0x0000C800) +#define RCC_ADC1MCLK_DIV27 ((uint32_t)0x0000D000) +#define RCC_ADC1MCLK_DIV28 ((uint32_t)0x0000D800) +#define RCC_ADC1MCLK_DIV29 ((uint32_t)0x0000E000) +#define RCC_ADC1MCLK_DIV30 ((uint32_t)0x0000E800) +#define RCC_ADC1MCLK_DIV31 ((uint32_t)0x0000F000) +#define RCC_ADC1MCLK_DIV32 ((uint32_t)0x0000F800) + +#define RCC_AHB_PERIPH_ADC1 ((uint32_t)0x00001000) +#define RCC_AHB_PERIPH_ADC2 ((uint32_t)0x00002000) +#define RCC_AHB_PERIPH_ADC3 ((uint32_t)0x00004000) +#define RCC_AHB_PERIPH_ADC4 ((uint32_t)0x00008000) + +#define SAMPT1_SMP_SET ((uint32_t)0x00000007) +#define SAMPT2_SMP_SET ((uint32_t)0x00000007) + +#define SQR4_SEQ_SET ((uint32_t)0x0000001F) +#define SQR3_SEQ_SET ((uint32_t)0x0000001F) +#define SQR2_SEQ_SET ((uint32_t)0x0000001F) +#define SQR1_SEQ_SET ((uint32_t)0x0000001F) + +#define CTRL1_CLR_MASK ((uint32_t)0xFFF0FEFF) +#define RSEQ1_CLR_MASK ((uint32_t)0xFF0FFFFF) +#define CTRL2_CLR_MASK ((uint32_t)0xFFF1F7FD) + +#define ADC_CH_0 ((uint8_t)0x00) +#define ADC_CH_1 ((uint8_t)0x01) +#define ADC_CH_2 ((uint8_t)0x02) +#define ADC_CH_3 ((uint8_t)0x03) +#define ADC_CH_4 ((uint8_t)0x04) +#define ADC_CH_5 ((uint8_t)0x05) +#define ADC_CH_6 ((uint8_t)0x06) +#define ADC_CH_7 ((uint8_t)0x07) +#define ADC_CH_8 ((uint8_t)0x08) +#define ADC_CH_9 ((uint8_t)0x09) +#define ADC_CH_10 ((uint8_t)0x0A) +#define ADC_CH_11 ((uint8_t)0x0B) +#define ADC_CH_12 ((uint8_t)0x0C) +#define ADC_CH_13 ((uint8_t)0x0D) +#define ADC_CH_14 ((uint8_t)0x0E) +#define ADC_CH_15 ((uint8_t)0x0F) +#define ADC_CH_16 ((uint8_t)0x10) +#define ADC_CH_17 ((uint8_t)0x11) +#define ADC_CH_18 ((uint8_t)0x12) + +#define ADC_WORKMODE_INDEPENDENT ((uint32_t)0x00000000) +#define ADC_WORKMODE_REG_INJECT_SIMULT ((uint32_t)0x00010000) +#define ADC_WORKMODE_REG_SIMULT_ALTER_TRIG ((uint32_t)0x00020000) +#define ADC_WORKMODE_INJ_SIMULT_FAST_INTERL ((uint32_t)0x00030000) +#define ADC_WORKMODE_INJ_SIMULT_SLOW_INTERL ((uint32_t)0x00040000) +#define ADC_WORKMODE_INJ_SIMULT ((uint32_t)0x00050000) +#define ADC_WORKMODE_REG_SIMULT ((uint32_t)0x00060000) +#define ADC_WORKMODE_FAST_INTERL ((uint32_t)0x00070000) +#define ADC_WORKMODE_SLOW_INTERL ((uint32_t)0x00080000) +#define ADC_WORKMODE_ALTER_TRIG ((uint32_t)0x00090000) + +#define ADC_EXT_TRIGCONV_T1_CC1 \ + ((uint32_t)0x00000000) /*!< For ADC1 and ADC2 */ +#define ADC_EXT_TRIGCONV_T1_CC2 \ + ((uint32_t)0x00020000) /*!< For ADC1 and ADC2 */ +#define ADC_EXT_TRIGCONV_T2_CC2 \ + ((uint32_t)0x00060000) /*!< For ADC1 and ADC2 */ +#define ADC_EXT_TRIGCONV_T1_CC3 \ + ((uint32_t)0x00040000) /*!< For ADC1, ADC2 , ADC3 and ADC4 */ +#define ADC_EXT_TRIGCONV_NONE \ + ((uint32_t)0x000E0000) /*!< For ADC1, ADC2 , ADC3 and ADC4 */ + +#define ADC_DAT_ALIGN_R ((uint32_t)0x00000000) +#define ADC_DAT_ALIGN_L ((uint32_t)0x00000800) + +#define ADC_FLAG_RDY ((uint8_t)0x20) +#define ADC_FLAG_PD_RDY ((uint8_t)0x40) + +#define CTRL2_AD_ON_SET ((uint32_t)0x00000001) +#define CTRL2_AD_ON_RESET ((uint32_t)0xFFFFFFFE) + +#define CTRL2_CAL_SET ((uint32_t)0x00000004) + +/* ADC Software start mask */ +#define CTRL2_EXT_TRIG_SWSTART_SET ((uint32_t)0x00500000) +#define CTRL2_EXT_TRIG_SWSTART_RESET ((uint32_t)0xFFAFFFFF) + +#define ADC_SAMP_TIME_1CYCLES5 ((uint8_t)0x00) +#define ADC_SAMP_TIME_7CYCLES5 ((uint8_t)0x01) +#define ADC_SAMP_TIME_13CYCLES5 ((uint8_t)0x02) +#define ADC_SAMP_TIME_28CYCLES5 ((uint8_t)0x03) +#define ADC_SAMP_TIME_41CYCLES5 ((uint8_t)0x04) +#define ADC_SAMP_TIME_55CYCLES5 ((uint8_t)0x05) +#define ADC_SAMP_TIME_71CYCLES5 ((uint8_t)0x06) +#define ADC_SAMP_TIME_239CYCLES5 ((uint8_t)0x07) + +#define ADC_FLAG_AWDG ((uint8_t)0x01) +#define ADC_FLAG_ENDC ((uint8_t)0x02) +#define ADC_FLAG_JENDC ((uint8_t)0x04) +#define ADC_FLAG_JSTR ((uint8_t)0x08) +#define ADC_FLAG_STR ((uint8_t)0x10) +#define ADC_FLAG_EOC_ANY ((uint8_t)0x20) +#define ADC_FLAG_JEOC_ANY ((uint8_t)0x40) + +#define ADC_STS_AWDG ((uint8_t)0x01) /*!< Analog watchdog flag */ +#define ADC_STS_ENDC ((uint8_t)0x02) /*!< End of conversion */ +#define ADC_STS_JENDC \ + ((uint8_t)0x04) /*!< Injected channel end of conversion */ +#define ADC_STS_JSTR ((uint8_t)0x08) /*!< Injected channel Start flag */ +#define ADC_STS_STR ((uint8_t)0x10) /*!< Regular channel Start flag */ +#define ADC_STS_ENDCA ((uint8_t)0x20) /*!< Any end of conversion */ +#define ADC_STS_JENDCA \ + ((uint8_t)0x40) /*!< Any injected channel end of conversion */ + +/* ADC DMA mask */ +#define CTRL2_DMA_SET ((uint32_t)0x00000100) +#define CTRL2_DMA_RESET ((uint32_t)0xFFFFFEFF) + +#define CTRL2_TSVREFE_SET ((uint32_t)0x00800000) +#define CTRL2_TSVREFE_RESET ((uint32_t)0xFF7FFFFF) +#define VREF1P2_CTRL (*(uint32_t *)(0x40001800 + 0x20)) +/******************* Bit definition for ADC_CTRL2 register + * ********************/ +#define ADC_CTRL2_ON ((uint32_t)0x00000001) /*!< A/D Converter ON / OFF */ +#define ADC_CTRL2_CTU ((uint32_t)0x00000002) /*!< Continuous Conversion */ +#define ADC_CTRL2_ENCAL ((uint32_t)0x00000004) /*!< A/D Calibration */ +#define ADC_CTRL2_ENDMA \ + ((uint32_t)0x00000100) /*!< Direct Memory access mode */ +#define ADC_CTRL2_ALIG ((uint32_t)0x00000800) /*!< Data Alignment */ + +#define ADC_CTRL2_EXTJSEL \ + ((uint32_t)0x00007000) /*!< INJ_EXT_SEL[2:0] bits (External event select \ + for injected group) */ +#define ADC_CTRL2_EXTJSEL_0 ((uint32_t)0x00001000) /*!< Bit 0 */ +#define ADC_CTRL2_EXTJSEL_1 ((uint32_t)0x00002000) /*!< Bit 1 */ +#define ADC_CTRL2_EXTJSEL_2 ((uint32_t)0x00004000) /*!< Bit 2 */ + +#define ADC_CTRL2_EXTJTRIG \ + ((uint32_t)0x00008000) /*!< External Trigger Conversion mode for injected \ + channels */ + +#define ADC_CTRL2_EXTRSEL \ + ((uint32_t)0x000E0000) /*!< EXTSEL[2:0] bits (External Event Select for \ + regular group) */ +#define ADC_CTRL2_EXTRSEL_0 ((uint32_t)0x00020000) /*!< Bit 0 */ +#define ADC_CTRL2_EXTRSEL_1 ((uint32_t)0x00040000) /*!< Bit 1 */ +#define ADC_CTRL2_EXTRSEL_2 ((uint32_t)0x00080000) /*!< Bit 2 */ + +#define ADC_CTRL2_EXTRTRIG \ + ((uint32_t)0x00100000) /*!< External Trigger Conversion mode for regular \ + channels */ +#define ADC_CTRL2_SWSTRJCH \ + ((uint32_t)0x00200000) /*!< Start Conversion of injected channels */ +#define ADC_CTRL2_SWSTRRCH \ + ((uint32_t)0x00400000) /*!< Start Conversion of regular channels */ +#define ADC_CTRL2_TEMPEN \ + ((uint32_t)0x00800000) /*!< Temperature Sensor and VREFINT Enable */ + +#define ADC_CTRL3_VABTMEN_MSK ((uint32_t)0x01L << 11) +#define ADC_CTRL3_DPWMOD_MSK ((uint32_t)0x01L << 10) +#define ADC_CTRL3_JENDCAIEN_MSK ((uint32_t)0x01L << 9) +#define ADC_CTRL3_ENDCAIEN_MSK ((uint32_t)0x01L << 8) +#define ADC_CTRL3_BPCAL_MSK ((uint32_t)0x01L << 7) +#define ADC_CTRL3_PDRDY_MSK ((uint32_t)0x01L << 6) +#define ADC_CTRL3_RDY_MSK ((uint32_t)0x01L << 5) +#define ADC_CTRL3_CKMOD_MSK ((uint32_t)0x01L << 4) +#define ADC_CTRL3_CALALD_MSK ((uint32_t)0x01L << 3) +#define ADC_CTRL3_CALDIF_MSK ((uint32_t)0x01L << 2) +#define ADC_CTRL3_RES_MSK ((uint32_t)0x03L << 0) + +void ADC_Init(ADC_Module* ADCx, ADC_InitType* ADC_InitStruct); +void ADC_ConfigRegularChannel(ADC_Module* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime); +#endif \ No newline at end of file diff --git a/lib/n32g45x/n32g45x_adc.c b/lib/n32g45x/n32g45x_adc.c new file mode 100644 index 000000000000..6621bcb21324 --- /dev/null +++ b/lib/n32g45x/n32g45x_adc.c @@ -0,0 +1,211 @@ +/***************************************************************************** + * Copyright (c) 2019, Nations Technologies Inc. + * + * All rights reserved. + * **************************************************************************** + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Nations' name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ****************************************************************************/ + +#include "stdint.h" +#include "n32g45x_adc.h" + +/** + * @brief Initializes the ADCx peripheral according to the specified parameters + * in the ADC_InitStruct. + * @param ADCx where x can be 1, 2 ,3 or 4 to select the ADC peripheral. + * @param ADC_InitStruct pointer to an ADC_InitType structure that contains + * the configuration information for the specified ADC peripheral. + */ +void ADC_Init(ADC_Module* ADCx, ADC_InitType* ADC_InitStruct) +{ + uint32_t tmpreg1 = 0; + uint8_t tmpreg2 = 0; + + /*---------------------------- ADCx CTRL1 Configuration -----------------*/ + /* Get the ADCx CTRL1 value */ + tmpreg1 = ADCx->CTRL1; + /* Clear DUALMOD and SCAN bits */ + tmpreg1 &= CTRL1_CLR_MASK; + /* Configure ADCx: Dual mode and scan conversion mode */ + /* Set DUALMOD bits according to WorkMode value */ + /* Set SCAN bit according to MultiChEn value */ + tmpreg1 |= (uint32_t)(ADC_InitStruct->WorkMode | ((uint32_t)ADC_InitStruct->MultiChEn << 8)); + /* Write to ADCx CTRL1 */ + ADCx->CTRL1 = tmpreg1; + + /*---------------------------- ADCx CTRL2 Configuration -----------------*/ + /* Get the ADCx CTRL2 value */ + tmpreg1 = ADCx->CTRL2; + /* Clear CONT, ALIGN and EXTSEL bits */ + tmpreg1 &= CTRL2_CLR_MASK; + /* Configure ADCx: external trigger event and continuous conversion mode */ + /* Set ALIGN bit according to DatAlign value */ + /* Set EXTSEL bits according to ExtTrigSelect value */ + /* Set CONT bit according to ContinueConvEn value */ + tmpreg1 |= (uint32_t)(ADC_InitStruct->DatAlign | ADC_InitStruct->ExtTrigSelect + | ((uint32_t)ADC_InitStruct->ContinueConvEn << 1)); + /* Write to ADCx CTRL2 */ + ADCx->CTRL2 = tmpreg1; + + /*---------------------------- ADCx RSEQ1 Configuration -----------------*/ + /* Get the ADCx RSEQ1 value */ + tmpreg1 = ADCx->RSEQ1; + /* Clear L bits */ + tmpreg1 &= RSEQ1_CLR_MASK; + /* Configure ADCx: regular channel sequence length */ + /* Set L bits according to ChsNumber value */ + tmpreg2 |= (uint8_t)(ADC_InitStruct->ChsNumber - (uint8_t)1); + tmpreg1 |= (uint32_t)tmpreg2 << 20; + /* Write to ADCx RSEQ1 */ + ADCx->RSEQ1 = tmpreg1; +} + + +/** + * @brief Configures for the selected ADC regular channel its corresponding + * rank in the sequencer and its sample time. + * @param ADCx where x can be 1, 2, 3 or 4 to select the ADC peripheral. + * @param ADC_Channel the ADC channel to configure. + * This parameter can be one of the following values: + * @arg ADC_CH_0 ADC Channel0 selected + * @arg ADC_CH_1 ADC Channel1 selected + * @arg ADC_CH_2 ADC Channel2 selected + * @arg ADC_CH_3 ADC Channel3 selected + * @arg ADC_CH_4 ADC Channel4 selected + * @arg ADC_CH_5 ADC Channel5 selected + * @arg ADC_CH_6 ADC Channel6 selected + * @arg ADC_CH_7 ADC Channel7 selected + * @arg ADC_CH_8 ADC Channel8 selected + * @arg ADC_CH_9 ADC Channel9 selected + * @arg ADC_CH_10 ADC Channel10 selected + * @arg ADC_CH_11 ADC Channel11 selected + * @arg ADC_CH_12 ADC Channel12 selected + * @arg ADC_CH_13 ADC Channel13 selected + * @arg ADC_CH_14 ADC Channel14 selected + * @arg ADC_CH_15 ADC Channel15 selected + * @arg ADC_CH_16 ADC Channel16 selected + * @arg ADC_CH_17 ADC Channel17 selected + * @arg ADC_CH_18 ADC Channel18 selected + * @param Rank The rank in the regular group sequencer. This parameter must be between 1 to 16. + * @param ADC_SampleTime The sample time value to be set for the selected channel. + * This parameter can be one of the following values: + * @arg ADC_SAMP_TIME_1CYCLES5 Sample time equal to 1.5 cycles + * @arg ADC_SAMP_TIME_7CYCLES5 Sample time equal to 7.5 cycles + * @arg ADC_SAMP_TIME_13CYCLES5 Sample time equal to 13.5 cycles + * @arg ADC_SAMP_TIME_28CYCLES5 Sample time equal to 28.5 cycles + * @arg ADC_SAMP_TIME_41CYCLES5 Sample time equal to 41.5 cycles + * @arg ADC_SAMP_TIME_55CYCLES5 Sample time equal to 55.5 cycles + * @arg ADC_SAMP_TIME_71CYCLES5 Sample time equal to 71.5 cycles + * @arg ADC_SAMP_TIME_239CYCLES5 Sample time equal to 239.5 cycles + */ + +void ADC_ConfigRegularChannel(ADC_Module* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime) +{ + uint32_t tmpreg1 = 0, tmpreg2 = 0; + + if (ADC_Channel == ADC_CH_18) + { + tmpreg1 = ADCx->SAMPT3; + tmpreg1 &= (~0x00000007); + tmpreg1 |= ADC_SampleTime; + ADCx->SAMPT3 = tmpreg1; + } + else if (ADC_Channel > ADC_CH_9) /* if ADC_CH_10 ... ADC_CH_17 is selected */ + { + /* Get the old register value */ + tmpreg1 = ADCx->SAMPT1; + /* Calculate the mask to clear */ + tmpreg2 = SAMPT1_SMP_SET << (3 * (ADC_Channel - 10)); + /* Clear the old channel sample time */ + tmpreg1 &= ~tmpreg2; + /* Calculate the mask to set */ + tmpreg2 = (uint32_t)ADC_SampleTime << (3 * (ADC_Channel - 10)); + /* Set the new channel sample time */ + tmpreg1 |= tmpreg2; + /* Store the new register value */ + ADCx->SAMPT1 = tmpreg1; + } + else /* ADC_Channel include in ADC_Channel_[0..9] */ + { + /* Get the old register value */ + tmpreg1 = ADCx->SAMPT2; + /* Calculate the mask to clear */ + tmpreg2 = SAMPT2_SMP_SET << (3 * ADC_Channel); + /* Clear the old channel sample time */ + tmpreg1 &= ~tmpreg2; + /* Calculate the mask to set */ + tmpreg2 = (uint32_t)ADC_SampleTime << (3 * ADC_Channel); + /* Set the new channel sample time */ + tmpreg1 |= tmpreg2; + /* Store the new register value */ + ADCx->SAMPT2 = tmpreg1; + } + /* For Rank 1 to 6 */ + if (Rank < 7) + { + /* Get the old register value */ + tmpreg1 = ADCx->RSEQ3; + /* Calculate the mask to clear */ + tmpreg2 = SQR3_SEQ_SET << (5 * (Rank - 1)); + /* Clear the old SQx bits for the selected rank */ + tmpreg1 &= ~tmpreg2; + /* Calculate the mask to set */ + tmpreg2 = (uint32_t)ADC_Channel << (5 * (Rank - 1)); + /* Set the SQx bits for the selected rank */ + tmpreg1 |= tmpreg2; + /* Store the new register value */ + ADCx->RSEQ3 = tmpreg1; + } + /* For Rank 7 to 12 */ + else if (Rank < 13) + { + /* Get the old register value */ + tmpreg1 = ADCx->RSEQ2; + /* Calculate the mask to clear */ + tmpreg2 = SQR2_SEQ_SET << (5 * (Rank - 7)); + /* Clear the old SQx bits for the selected rank */ + tmpreg1 &= ~tmpreg2; + /* Calculate the mask to set */ + tmpreg2 = (uint32_t)ADC_Channel << (5 * (Rank - 7)); + /* Set the SQx bits for the selected rank */ + tmpreg1 |= tmpreg2; + /* Store the new register value */ + ADCx->RSEQ2 = tmpreg1; + } + /* For Rank 13 to 16 */ + else + { + /* Get the old register value */ + tmpreg1 = ADCx->RSEQ1; + /* Calculate the mask to clear */ + tmpreg2 = SQR1_SEQ_SET << (5 * (Rank - 13)); + /* Clear the old SQx bits for the selected rank */ + tmpreg1 &= ~tmpreg2; + /* Calculate the mask to set */ + tmpreg2 = (uint32_t)ADC_Channel << (5 * (Rank - 13)); + /* Set the SQx bits for the selected rank */ + tmpreg1 |= tmpreg2; + /* Store the new register value */ + ADCx->RSEQ1 = tmpreg1; + } +} + diff --git a/scripts/flash-linux.sh b/scripts/flash-linux.sh index cc808aa85ada..bd3b4f63ce28 100755 --- a/scripts/flash-linux.sh +++ b/scripts/flash-linux.sh @@ -7,10 +7,17 @@ if [ "$EUID" -ne 0 ]; then fi set -e +# Setting build output directory +if [ -z "${1}" ]; then + out='out' +else + out=${1} +fi + # Install new micro-controller code echo "Installing micro-controller code to /usr/local/bin/" rm -f /usr/local/bin/klipper_mcu -cp out/klipper.elf /usr/local/bin/klipper_mcu +cp ${out}/klipper.elf /usr/local/bin/klipper_mcu sync # Restart (if system install script present) diff --git a/scripts/install-ubuntu-22.04.sh b/scripts/install-ubuntu-22.04.sh new file mode 100644 index 000000000000..e2b9580f5b05 --- /dev/null +++ b/scripts/install-ubuntu-22.04.sh @@ -0,0 +1,102 @@ +#!/bin/bash +# This script installs Klipper on an Ubuntu 22.04 ("Jammy") machine + +PYTHONDIR="${HOME}/klippy-env" +SYSTEMDDIR="/etc/systemd/system" +KLIPPER_USER=$USER +KLIPPER_GROUP=$KLIPPER_USER + +# Step 1: Install system packages +install_packages() +{ + # Packages for python cffi + PKGLIST="virtualenv python3-dev libffi-dev build-essential" + # kconfig requirements + PKGLIST="${PKGLIST} libncurses-dev" + # hub-ctrl + PKGLIST="${PKGLIST} libusb-dev" + # AVR chip installation and building + PKGLIST="${PKGLIST} avrdude gcc-avr binutils-avr avr-libc" + # ARM chip installation and building + PKGLIST="${PKGLIST} stm32flash dfu-util libnewlib-arm-none-eabi" + PKGLIST="${PKGLIST} gcc-arm-none-eabi binutils-arm-none-eabi libusb-1.0" + + # Update system package info + report_status "Running apt-get update..." + sudo apt-get update + + # Install desired packages + report_status "Installing packages..." + sudo apt-get install --yes ${PKGLIST} +} + +# Step 2: Create python virtual environment +create_virtualenv() +{ + report_status "Updating python virtual environment..." + + # Create virtualenv if it doesn't already exist + [ ! -d ${PYTHONDIR} ] && virtualenv -p python3 ${PYTHONDIR} + + # Install/update dependencies + ${PYTHONDIR}/bin/pip install -r ${SRCDIR}/scripts/klippy-requirements.txt +} + +# Step 3: Install startup script +install_script() +{ +# Create systemd service file + KLIPPER_LOG=/tmp/klippy.log + report_status "Installing system start script..." + sudo /bin/sh -c "cat > $SYSTEMDDIR/klipper.service" << EOF +#Systemd service file for klipper +[Unit] +Description=Starts klipper on startup +After=network.target + +[Install] +WantedBy=multi-user.target + +[Service] +Type=simple +User=$KLIPPER_USER +RemainAfterExit=yes +ExecStart=${PYTHONDIR}/bin/python ${SRCDIR}/klippy/klippy.py ${HOME}/printer.cfg -l ${KLIPPER_LOG} +EOF +# Use systemctl to enable the klipper systemd service script + sudo systemctl enable klipper.service +} + +# Step 4: Start host software +start_software() +{ + report_status "Launching Klipper host software..." + sudo systemctl start klipper +} + +# Helper functions +report_status() +{ + echo -e "\n\n###### $1" +} + +verify_ready() +{ + if [ "$EUID" -eq 0 ]; then + echo "This script must not run as root" + exit -1 + fi +} + +# Force script to exit if an error occurs +set -e + +# Find SRCDIR from the pathname of this script +SRCDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )" + +# Run installation steps defined above +verify_ready +install_packages +create_virtualenv +install_script +start_software diff --git a/src/generic/canserial.c b/src/generic/canserial.c index 0607e4893e91..d56235f57fe7 100644 --- a/src/generic/canserial.c +++ b/src/generic/canserial.c @@ -224,7 +224,7 @@ canserial_notify_rx(void) DECL_CONSTANT("RECEIVE_WINDOW", ARRAY_SIZE(CanData.receive_buf)); // Handle incoming data (called from IRQ handler) -int +void canserial_process_data(struct canbus_msg *msg) { uint32_t id = msg->id; @@ -233,7 +233,7 @@ canserial_process_data(struct canbus_msg *msg) int rpos = CanData.receive_pos; uint32_t len = CANMSG_DATA_LEN(msg); if (len > sizeof(CanData.receive_buf) - rpos) - return -1; + return; memcpy(&CanData.receive_buf[rpos], msg->data, len); CanData.receive_pos = rpos + len; canserial_notify_rx(); @@ -243,13 +243,12 @@ canserial_process_data(struct canbus_msg *msg) uint32_t pushp = CanData.admin_push_pos; if (pushp >= CanData.admin_pull_pos + ARRAY_SIZE(CanData.admin_queue)) // No space - drop message - return -1; + return; uint32_t pos = pushp % ARRAY_SIZE(CanData.admin_queue); memcpy(&CanData.admin_queue[pos], msg, sizeof(*msg)); CanData.admin_push_pos = pushp + 1; canserial_notify_rx(); } - return 0; } // Remove from the receive buffer the given number of bytes diff --git a/src/generic/canserial.h b/src/generic/canserial.h index e8f3767fab18..3dd5cd9deae4 100644 --- a/src/generic/canserial.h +++ b/src/generic/canserial.h @@ -9,7 +9,7 @@ // canserial.c void canserial_notify_tx(void); struct canbus_msg; -int canserial_process_data(struct canbus_msg *msg); +void canserial_process_data(struct canbus_msg *msg); void canserial_set_uuid(uint8_t *raw_uuid, uint32_t raw_uuid_len); #endif // canserial.h diff --git a/src/generic/usb_canbus.c b/src/generic/usb_canbus.c index 3cb4bdd06fef..d776d45f248a 100644 --- a/src/generic/usb_canbus.c +++ b/src/generic/usb_canbus.c @@ -112,12 +112,12 @@ static struct usbcan_data { uint8_t host_status; // Canbus data routed locally - uint8_t notify_local; + uint8_t notify_local, usb_send_busy; uint32_t assigned_id; // Data from physical canbus interface uint32_t pull_pos, push_pos; - struct canbus_msg queue[8]; + struct canbus_msg queue[32]; } UsbCan; enum { @@ -166,21 +166,25 @@ send_frame(struct canbus_msg *msg) } // Send any pending hw frames to host -static int +static void drain_hw_queue(void) { + uint32_t pull_pos = UsbCan.pull_pos; for (;;) { uint32_t push_pos = readl(&UsbCan.push_pos); - uint32_t pull_pos = UsbCan.pull_pos; - if (push_pos != pull_pos) { - uint32_t pos = pull_pos % ARRAY_SIZE(UsbCan.queue); - int ret = send_frame(&UsbCan.queue[pos]); - if (ret < 0) - return -1; - UsbCan.pull_pos = pull_pos + 1; - continue; + if (push_pos == pull_pos) { + // No more data to send + UsbCan.usb_send_busy = 0; + return; + } + uint32_t pos = pull_pos % ARRAY_SIZE(UsbCan.queue); + int ret = send_frame(&UsbCan.queue[pos]); + if (ret < 0) { + // USB is busy - retry later + UsbCan.usb_send_busy = 1; + return; } - return 0; + UsbCan.pull_pos = pull_pos = pull_pos + 1; } } @@ -189,12 +193,11 @@ usbcan_task(void) { if (!sched_check_wake(&UsbCan.wake)) return; - for (;;) { - // Send any pending hw frames to host - int ret = drain_hw_queue(); - if (ret < 0) - return; + // Send any pending hw frames to host + drain_hw_queue(); + + for (;;) { // See if previous host frame needs to be transmitted uint_fast8_t host_status = UsbCan.host_status; if (host_status & (HS_TX_HW | HS_TX_LOCAL)) { @@ -204,62 +207,55 @@ usbcan_task(void) msg.dlc = gs->can_dlc; msg.data32[0] = gs->data32[0]; msg.data32[1] = gs->data32[1]; + if (host_status & HS_TX_LOCAL) { + canserial_process_data(&msg); + UsbCan.host_status = host_status = host_status & ~HS_TX_LOCAL; + } if (host_status & HS_TX_HW) { - ret = canhw_send(&msg); + int ret = canhw_send(&msg); if (ret < 0) - return; + break; UsbCan.host_status = host_status = host_status & ~HS_TX_HW; } - if (host_status & HS_TX_LOCAL) { - ret = canserial_process_data(&msg); - if (ret < 0) { - usb_notify_bulk_out(); - return; - } - UsbCan.host_status = host_status & ~HS_TX_LOCAL; - } - continue; } // Send any previous echo frames if (host_status) { - ret = usb_send_bulk_in(&UsbCan.host_frame - , sizeof(UsbCan.host_frame)); + if (UsbCan.usb_send_busy) + // Don't send echo frame until other traffic is sent + return; + int ret = usb_send_bulk_in(&UsbCan.host_frame + , sizeof(UsbCan.host_frame)); if (ret < 0) return; UsbCan.host_status = 0; - continue; } - // See if can read a new frame from host - ret = usb_read_bulk_out(&UsbCan.host_frame, USB_CDC_EP_BULK_OUT_SIZE); - if (ret > 0) { - uint32_t id = UsbCan.host_frame.can_id; - UsbCan.host_status = HS_TX_ECHO | HS_TX_HW; - if (id == CANBUS_ID_ADMIN) - UsbCan.host_status = HS_TX_ECHO | HS_TX_HW | HS_TX_LOCAL; - else if (UsbCan.assigned_id && UsbCan.assigned_id == id) - UsbCan.host_status = HS_TX_ECHO | HS_TX_LOCAL; - continue; - } - - // No more work to be done - if (UsbCan.notify_local) { - UsbCan.notify_local = 0; - canserial_notify_tx(); - } - return; + // Read next frame from host + int ret = usb_read_bulk_out(&UsbCan.host_frame + , USB_CDC_EP_BULK_OUT_SIZE); + if (ret <= 0) + // No frame available - no more work to be done + break; + uint32_t id = UsbCan.host_frame.can_id; + UsbCan.host_status = HS_TX_ECHO | HS_TX_HW; + if (id == CANBUS_ID_ADMIN) + UsbCan.host_status = HS_TX_ECHO | HS_TX_HW | HS_TX_LOCAL; + else if (UsbCan.assigned_id && UsbCan.assigned_id == id) + UsbCan.host_status = HS_TX_ECHO | HS_TX_LOCAL; } + + if (UsbCan.notify_local && !UsbCan.usb_send_busy) + canserial_notify_tx(); } DECL_TASK(usbcan_task); int canbus_send(struct canbus_msg *msg) { - int ret = drain_hw_queue(); - if (ret < 0) + if (UsbCan.usb_send_busy) goto retry_later; - ret = send_frame(msg); + int ret = send_frame(msg); if (ret < 0) goto retry_later; UsbCan.notify_local = 0; diff --git a/src/linux/Makefile b/src/linux/Makefile index f234c3af4552..7c1de7c1f88b 100644 --- a/src/linux/Makefile +++ b/src/linux/Makefile @@ -11,4 +11,4 @@ CFLAGS_klipper.elf += -lutil -lrt -lpthread flash: $(OUT)klipper.elf @echo " Flashing" - $(Q)sudo ./scripts/flash-linux.sh + $(Q)sudo ./scripts/flash-linux.sh $(OUT) diff --git a/src/linux/main.c b/src/linux/main.c index c8cb3dfd46d3..f9ea3f6daaa8 100644 --- a/src/linux/main.c +++ b/src/linux/main.c @@ -4,10 +4,11 @@ // // This file may be distributed under the terms of the GNU GPLv3 license. -#include // sched_setscheduler +#include // sched_setscheduler sched_get_priority_max #include // fprintf #include // memset #include // getopt +#include // mlockall MCL_CURRENT MCL_FUTURE #include "board/misc.h" // console_sendf #include "command.h" // DECL_CONSTANT #include "internal.h" // console_setup @@ -25,12 +26,18 @@ realtime_setup(void) { struct sched_param sp; memset(&sp, 0, sizeof(sp)); - sp.sched_priority = 1; + sp.sched_priority = sched_get_priority_max(SCHED_FIFO) / 2; int ret = sched_setscheduler(0, SCHED_FIFO, &sp); if (ret < 0) { report_errno("sched_setscheduler", ret); return -1; } + // Lock ourselves into memory + ret = mlockall(MCL_CURRENT | MCL_FUTURE); + if (ret) { + report_errno("mlockall", ret); + return -1; + } return 0; } diff --git a/src/sensor_mpu9250.c b/src/sensor_mpu9250.c index d7f3092867ce..51df5a711d31 100644 --- a/src/sensor_mpu9250.c +++ b/src/sensor_mpu9250.c @@ -1,5 +1,6 @@ // Support for gathering acceleration data from mpu9250 chip // +// Copyright (C) 2023 Matthew Swabey // Copyright (C) 2022 Harry Beyel // Copyright (C) 2020-2021 Kevin O'Connor // @@ -24,6 +25,7 @@ #define AR_USER_CTRL 0x6A #define AR_FIFO_COUNT_H 0x72 #define AR_FIFO 0x74 +#define AR_INT_STATUS 0x3A #define SET_ENABLE_FIFO 0x08 #define SET_DISABLE_FIFO 0x00 @@ -35,15 +37,17 @@ #define SET_PWR_2_ACCEL 0x07 // only enable accelerometers #define SET_PWR_2_NONE 0x3F // disable all sensors +#define FIFO_OVERFLOW_INT 0x10 + #define BYTES_PER_FIFO_ENTRY 6 struct mpu9250 { struct timer timer; uint32_t rest_ticks; struct i2cdev_s *i2c; - uint16_t sequence, limit_count; + uint16_t sequence, limit_count, fifo_max, fifo_pkts_bytes; uint8_t flags, data_count; - // data size must be <= 255 due to i2c api + // msg size must be <= 255 due to Klipper api // = SAMPLES_PER_BLOCK (from mpu9250.py) * BYTES_PER_FIFO_ENTRY + 1 uint8_t data[48]; }; @@ -55,14 +59,16 @@ enum { static struct task_wake mpu9250_wake; // Reads the fifo byte count from the device. -uint16_t +static uint16_t get_fifo_status (struct mpu9250 *mp) { - uint8_t regs[] = {AR_FIFO_COUNT_H}; + uint8_t reg[] = {AR_FIFO_COUNT_H}; uint8_t msg[2]; - i2c_read(mp->i2c->i2c_config, sizeof(regs), regs, 2, msg); + i2c_read(mp->i2c->i2c_config, sizeof(reg), reg, sizeof(msg), msg); msg[0] = 0x1F & msg[0]; // discard 3 MSB per datasheet - return (((uint16_t)msg[0]) << 8 | msg[1]); + uint16_t bytes_to_read = ((uint16_t)msg[0]) << 8 | msg[1]; + if (bytes_to_read > mp->fifo_max) mp->fifo_max = bytes_to_read; + return bytes_to_read; } // Event handler that wakes mpu9250_task() periodically @@ -120,42 +126,30 @@ mp9250_reschedule_timer(struct mpu9250 *mp) static void mp9250_query(struct mpu9250 *mp, uint8_t oid) { - // Check fifo status - uint16_t fifo_bytes = get_fifo_status(mp); - if (fifo_bytes >= AR_FIFO_SIZE - BYTES_PER_FIFO_ENTRY) - mp->limit_count++; - - // Read data - // FIFO data are: [Xh, Xl, Yh, Yl, Zh, Zl] - uint8_t reg = AR_FIFO; - uint8_t bytes_to_read = fifo_bytes < sizeof(mp->data) - mp->data_count ? - fifo_bytes & 0xFF : - (sizeof(mp->data) - mp->data_count) & 0xFF; + // Find remaining space in report buffer + uint8_t data_space = sizeof(mp->data) - mp->data_count; - // round down to nearest full packet of data - bytes_to_read = bytes_to_read / BYTES_PER_FIFO_ENTRY * BYTES_PER_FIFO_ENTRY; + // If not enough bytes to fill report read MPU FIFO's fill + if (mp->fifo_pkts_bytes < data_space) { + mp->fifo_pkts_bytes = get_fifo_status(mp) / BYTES_PER_FIFO_ENTRY + * BYTES_PER_FIFO_ENTRY; + } - // Extract x, y, z measurements into data holder and report - if (bytes_to_read > 0) { + // If we have enough bytes to fill the buffer do it and send report + if (mp->fifo_pkts_bytes >= data_space) { + uint8_t reg = AR_FIFO; i2c_read(mp->i2c->i2c_config, sizeof(reg), ®, - bytes_to_read, &mp->data[mp->data_count]); - mp->data_count += bytes_to_read; - - // report data when buffer is full - if (mp->data_count + BYTES_PER_FIFO_ENTRY > sizeof(mp->data)) { - mp9250_report(mp, oid); - } + data_space, &mp->data[mp->data_count]); + mp->data_count += data_space; + mp->fifo_pkts_bytes -= data_space; + mp9250_report(mp, oid); } - // check if we need to run the task again (more packets in fifo?) - if ( bytes_to_read > 0 && - bytes_to_read / BYTES_PER_FIFO_ENTRY < - fifo_bytes / BYTES_PER_FIFO_ENTRY) { - // more data still ready in the fifo buffer + // If we have enough bytes remaining to fill another report wake again + // otherwise schedule timed wakeup + if (mp->fifo_pkts_bytes > data_space) { sched_wake_task(&mpu9250_wake); - } - else if (mp->flags & AX_RUNNING) { - // No more fifo data, but actively running. Sleep until next check + } else if (mp->flags & AX_RUNNING) { sched_del_timer(&mp->timer); mp->flags &= ~AX_PENDING; mp9250_reschedule_timer(mp); @@ -182,6 +176,9 @@ mp9250_start(struct mpu9250 *mp, uint8_t oid) msg[1] = SET_USER_FIFO_EN; // enable FIFO buffer access i2c_write(mp->i2c->i2c_config, sizeof(msg), msg); + uint8_t int_reg[] = {AR_INT_STATUS}; // clear FIFO overflow flag + i2c_read(mp->i2c->i2c_config, sizeof(int_reg), int_reg, 1, msg); + msg[0] = AR_FIFO_EN; msg[1] = SET_ENABLE_FIFO; // enable accel output to FIFO i2c_write(mp->i2c->i2c_config, sizeof(msg), msg); @@ -203,18 +200,24 @@ mp9250_stop(struct mpu9250 *mp, uint8_t oid) i2c_write(mp->i2c->i2c_config, sizeof(msg), msg); uint32_t end2_time = timer_read_time(); - // Drain any measurements still in fifo - uint16_t fifo_bytes = get_fifo_status(mp); - while (fifo_bytes >= BYTES_PER_FIFO_ENTRY) { - mp9250_query(mp, oid); - fifo_bytes = get_fifo_status(mp); - } + // Detect if a FIFO overrun occured + uint8_t int_reg[] = {AR_INT_STATUS}; + uint8_t int_msg; + i2c_read(mp->i2c->i2c_config, sizeof(int_reg), int_reg, sizeof(int_msg), + &int_msg); + if (int_msg & FIFO_OVERFLOW_INT) + mp->limit_count++; // Report final data if (mp->data_count > 0) mp9250_report(mp, oid); + uint16_t bytes_to_read = get_fifo_status(mp); mp9250_status(mp, oid, end1_time, end2_time, - fifo_bytes / BYTES_PER_FIFO_ENTRY); + bytes_to_read / BYTES_PER_FIFO_ENTRY); + + // Uncomment and rebuilt to check for FIFO overruns when tuning + //output("mpu9240 limit_count=%u fifo_max=%u", + // mp->limit_count, mp->fifo_max); } void @@ -232,8 +235,11 @@ command_query_mpu9250(uint32_t *args) mp->timer.waketime = args[1]; mp->rest_ticks = args[2]; mp->flags = AX_HAVE_START; - mp->sequence = mp->limit_count = 0; + mp->sequence = 0; + mp->limit_count = 0; mp->data_count = 0; + mp->fifo_max = 0; + mp->fifo_pkts_bytes = 0; sched_add_timer(&mp->timer); } DECL_COMMAND(command_query_mpu9250, @@ -245,12 +251,12 @@ command_query_mpu9250_status(uint32_t *args) struct mpu9250 *mp = oid_lookup(args[0], command_config_mpu9250); uint8_t msg[2]; uint32_t time1 = timer_read_time(); - uint8_t regs[] = {AR_FIFO_COUNT_H}; - i2c_read(mp->i2c->i2c_config, 1, regs, 2, msg); + uint8_t reg[] = {AR_FIFO_COUNT_H}; + i2c_read(mp->i2c->i2c_config, sizeof(reg), reg, sizeof(msg), msg); uint32_t time2 = timer_read_time(); msg[0] = 0x1F & msg[0]; // discard 3 MSB - uint16_t fifo_bytes = (((uint16_t)msg[0]) << 8) | msg[1]; - mp9250_status(mp, args[0], time1, time2, fifo_bytes / BYTES_PER_FIFO_ENTRY); + mp9250_status(mp, args[0], time1, time2, mp->fifo_pkts_bytes + / BYTES_PER_FIFO_ENTRY); } DECL_COMMAND(command_query_mpu9250_status, "query_mpu9250_status oid=%c"); diff --git a/src/stm32/Kconfig b/src/stm32/Kconfig index 50db29d2536d..5d82f9c3f6db 100644 --- a/src/stm32/Kconfig +++ b/src/stm32/Kconfig @@ -7,7 +7,7 @@ config STM32_SELECT default y select HAVE_GPIO select HAVE_GPIO_ADC - select HAVE_GPIO_I2C if !(MACH_STM32F031 || MACH_STM32H7) + select HAVE_GPIO_I2C if !(MACH_STM32F031) select HAVE_GPIO_SPI if !MACH_STM32F031 select HAVE_GPIO_SDIO if MACH_STM32F4 select HAVE_GPIO_HARD_PWM if MACH_STM32F1 || MACH_STM32F4 || MACH_STM32G0 || MACH_STM32H7 @@ -97,6 +97,14 @@ choice config MACH_STM32L412 bool "STM32L412" select MACH_STM32L4 + config MACH_N32G452 + bool "Nation N32G452" + select MACH_N32G45x + select MACH_STM32F1 + config MACH_N32G455 + bool "Nation N32G455" + select MACH_N32G45x + select MACH_STM32F1 endchoice config MACH_STM32F103x6 @@ -127,10 +135,12 @@ config MACH_STM32F4x5 # F405, F407, F429 series bool config MACH_STM32L4 bool +config MACH_N32G45x + bool config HAVE_STM32_USBFS bool default y if MACH_STM32F0x2 || MACH_STM32G0Bx || MACH_STM32L4 || MACH_STM32G4 - default y if (MACH_STM32F103 || MACH_STM32F070) && !STM32_CLOCK_REF_INTERNAL + default y if (MACH_STM32F1 || MACH_STM32F070) && !STM32_CLOCK_REF_INTERNAL config HAVE_STM32_USBOTG bool default y if MACH_STM32F2 || MACH_STM32F4 || MACH_STM32H7 @@ -144,7 +154,7 @@ config HAVE_STM32_USBCANBUS bool depends on HAVE_STM32_USBFS || HAVE_STM32_USBOTG depends on HAVE_STM32_CANBUS || HAVE_STM32_FDCANBUS - depends on !MACH_STM32F103 + depends on !MACH_STM32F1 default y config MCU @@ -169,6 +179,7 @@ config MCU default "stm32h743xx" if MACH_STM32H743 default "stm32h750xx" if MACH_STM32H750 default "stm32l412xx" if MACH_STM32L412 + default "stm32f103xe" if MACH_N32G45x config CLOCK_FREQ int @@ -183,6 +194,8 @@ config CLOCK_FREQ default 150000000 if MACH_STM32G431 default 400000000 if MACH_STM32H7 # 400Mhz is max Klipper currently supports default 80000000 if MACH_STM32L412 + default 64000000 if MACH_N32G45x && STM32_CLOCK_REF_INTERNAL + default 128000000 if MACH_N32G45x config FLASH_SIZE hex @@ -195,6 +208,7 @@ config FLASH_SIZE default 0x20000 if MACH_STM32G0 || MACH_STM32G431 default 0x20000 if MACH_STM32H750 default 0x200000 if MACH_STM32H743 + default 0x20000 if MACH_N32G45x config FLASH_BOOT_ADDRESS hex @@ -219,6 +233,7 @@ config RAM_SIZE default 0x9000 if MACH_STM32G07x default 0x24000 if MACH_STM32G0Bx default 0x20000 if MACH_STM32H7 + default 0x10000 if MACH_N32G45x config STACK_SIZE int @@ -251,11 +266,11 @@ config STM32_DFU_ROM_ADDRESS choice prompt "Bootloader offset" config STM32_FLASH_START_2000 - bool "8KiB bootloader" if MACH_STM32F103 || MACH_STM32F070 || MACH_STM32G0 || MACH_STM32F0x2 + bool "8KiB bootloader" if MACH_STM32F1 || MACH_STM32F070 || MACH_STM32G0 || MACH_STM32F0x2 config STM32_FLASH_START_5000 bool "20KiB bootloader" if MACH_STM32F103 config STM32_FLASH_START_7000 - bool "28KiB bootloader" if MACH_STM32F103 + bool "28KiB bootloader" if MACH_STM32F1 config STM32_FLASH_START_8000 bool "32KiB bootloader" if MACH_STM32F1 || MACH_STM32F2 || MACH_STM32F4 config STM32_FLASH_START_8800 @@ -385,6 +400,10 @@ choice bool "Serial (on UART4 PA0/PA1)" depends on MACH_STM32H7 select SERIAL + config STM32_SERIAL_USART5 + bool "Serial (on USART5 PD2/PD3)" if LOW_LEVEL_OPTIONS + depends on MACH_STM32G0Bx + select SERIAL config STM32_CANBUS_PA11_PA12 bool "CAN bus (on PA11/PA12)" depends on HAVE_STM32_CANBUS || HAVE_STM32_FDCANBUS diff --git a/src/stm32/Makefile b/src/stm32/Makefile index 390ad8d5ea64..e5dac2aac2d0 100644 --- a/src/stm32/Makefile +++ b/src/stm32/Makefile @@ -6,6 +6,7 @@ CROSS_PREFIX=arm-none-eabi- dirs-y += src/stm32 src/generic lib/fast-hash dirs-$(CONFIG_MACH_STM32F0) += lib/stm32f0 dirs-$(CONFIG_MACH_STM32F1) += lib/stm32f1 +dirs-$(CONFIG_MACH_N32G45x) += lib/n32g45x dirs-$(CONFIG_MACH_STM32F2) += lib/stm32f2 dirs-$(CONFIG_MACH_STM32F4) += lib/stm32f4 dirs-$(CONFIG_MACH_STM32G0) += lib/stm32g0 @@ -17,7 +18,9 @@ MCU := $(shell echo $(CONFIG_MCU)) MCU_UPPER := $(shell echo $(CONFIG_MCU) | tr a-z A-Z | tr X x) CFLAGS-$(CONFIG_MACH_STM32F0) += -mcpu=cortex-m0 -Ilib/stm32f0/include -CFLAGS-$(CONFIG_MACH_STM32F1) += -mcpu=cortex-m3 -Ilib/stm32f1/include +CFLAGS-$(CONFIG_MACH_STM32F103) += -mcpu=cortex-m3 +CFLAGS-$(CONFIG_MACH_N32G45x) += -mcpu=cortex-m4 -Ilib/n32g45x/include +CFLAGS-$(CONFIG_MACH_STM32F1) += -Ilib/stm32f1/include CFLAGS-$(CONFIG_MACH_STM32F2) += -mcpu=cortex-m3 -Ilib/stm32f2/include CFLAGS-$(CONFIG_MACH_STM32F4) += -mcpu=cortex-m4 -Ilib/stm32f4/include CFLAGS-$(CONFIG_MACH_STM32G0) += -mcpu=cortex-m0plus -Ilib/stm32g0/include @@ -38,9 +41,11 @@ src-$(CONFIG_MACH_STM32F0) += ../lib/stm32f0/system_stm32f0xx.c src-$(CONFIG_MACH_STM32F0) += generic/timer_irq.c stm32/stm32f0_timer.c src-$(CONFIG_MACH_STM32F0) += stm32/stm32f0.c stm32/gpioperiph.c src-$(CONFIG_MACH_STM32F0) += stm32/stm32f0_adc.c stm32/stm32f0_i2c.c -src-$(CONFIG_MACH_STM32F1) += ../lib/stm32f1/system_stm32f1xx.c -src-$(CONFIG_MACH_STM32F1) += stm32/stm32f1.c generic/armcm_timer.c -src-$(CONFIG_MACH_STM32F1) += stm32/adc.c stm32/i2c.c +src-$(CONFIG_MACH_STM32F103) += ../lib/stm32f1/system_stm32f1xx.c +src-$(CONFIG_MACH_STM32F103) += stm32/adc.c +src-$(CONFIG_MACH_N32G45x) += ../lib/stm32f1/system_stm32f1xx.c +src-$(CONFIG_MACH_N32G45x) += ../lib/n32g45x/n32g45x_adc.c stm32/n32g45x_adc.c +src-$(CONFIG_MACH_STM32F1) += stm32/stm32f1.c generic/armcm_timer.c stm32/i2c.c src-$(CONFIG_MACH_STM32F2) += ../lib/stm32f2/system_stm32f2xx.c src-$(CONFIG_MACH_STM32F2) += stm32/stm32f4.c generic/armcm_timer.c src-$(CONFIG_MACH_STM32F2) += stm32/gpioperiph.c stm32/adc.c stm32/i2c.c @@ -57,6 +62,7 @@ src-$(CONFIG_MACH_STM32G4) += stm32/stm32f0_i2c.c src-$(CONFIG_MACH_STM32H7) += ../lib/stm32h7/system_stm32h7xx.c src-$(CONFIG_MACH_STM32H7) += stm32/stm32h7.c generic/armcm_timer.c src-$(CONFIG_MACH_STM32H7) += stm32/gpioperiph.c stm32/stm32h7_adc.c +src-$(CONFIG_MACH_STM32H7) += stm32/stm32f0_i2c.c src-$(CONFIG_MACH_STM32L4) += ../lib/stm32l4/system_stm32l4xx.c src-$(CONFIG_MACH_STM32L4) += stm32/stm32l4.c generic/armcm_timer.c src-$(CONFIG_MACH_STM32L4) += stm32/gpioperiph.c diff --git a/src/stm32/hard_pwm.c b/src/stm32/hard_pwm.c index 0aafe7d49bd1..a15b1c375568 100644 --- a/src/stm32/hard_pwm.c +++ b/src/stm32/hard_pwm.c @@ -20,7 +20,7 @@ struct gpio_pwm_info { }; static const struct gpio_pwm_info pwm_regs[] = { -#if CONFIG_MACH_STM32F103 +#if CONFIG_MACH_STM32F1 {TIM2, GPIO('A', 0), 1, GPIO_FUNCTION(2)}, {TIM2, GPIO('A', 1), 2, GPIO_FUNCTION(2)}, {TIM2, GPIO('A', 2), 3, GPIO_FUNCTION(2)}, @@ -117,12 +117,12 @@ static const struct gpio_pwm_info pwm_regs[] = { {TIM1, GPIO('B', 3), 2, GPIO_FUNCTION(1)}, {TIM3, GPIO('B', 4), 1, GPIO_FUNCTION(1)}, {TIM3, GPIO('B', 5), 2, GPIO_FUNCTION(1)}, -#if CONFIG_MACH_STM32G0Bx + #if CONFIG_MACH_STM32G0Bx {TIM4, GPIO('B', 6), 1, GPIO_FUNCTION(9)}, {TIM4, GPIO('B', 7), 2, GPIO_FUNCTION(9)}, {TIM4, GPIO('B', 8), 3, GPIO_FUNCTION(9)}, {TIM4, GPIO('B', 9), 4, GPIO_FUNCTION(9)}, -#endif + #endif {TIM15, GPIO('B', 14), 1, GPIO_FUNCTION(5)}, {TIM15, GPIO('B', 15), 2, GPIO_FUNCTION(5)}, {TIM15, GPIO('C', 1), 1, GPIO_FUNCTION(2)}, @@ -136,12 +136,12 @@ static const struct gpio_pwm_info pwm_regs[] = { {TIM14, GPIO('C', 12), 1, GPIO_FUNCTION(2)}, {TIM16, GPIO('D', 0), 1, GPIO_FUNCTION(2)}, {TIM17, GPIO('D', 1), 1, GPIO_FUNCTION(2)}, -#if CONFIG_MACH_STM32G0Bx + #if CONFIG_MACH_STM32G0Bx {TIM4, GPIO('D', 12), 1, GPIO_FUNCTION(2)}, {TIM4, GPIO('D', 13), 2, GPIO_FUNCTION(2)}, {TIM4, GPIO('D', 14), 3, GPIO_FUNCTION(2)}, {TIM4, GPIO('D', 15), 4, GPIO_FUNCTION(2)}, -#endif + #endif {TIM3, GPIO('E', 3), 1, GPIO_FUNCTION(1)}, {TIM3, GPIO('E', 4), 2, GPIO_FUNCTION(1)}, {TIM3, GPIO('E', 5), 3, GPIO_FUNCTION(1)}, diff --git a/src/stm32/n32g45x_adc.c b/src/stm32/n32g45x_adc.c new file mode 100644 index 000000000000..d27e70c9e445 --- /dev/null +++ b/src/stm32/n32g45x_adc.c @@ -0,0 +1,185 @@ +// ADC functions on N32G45x +// +// Copyright (C) 2022-2023 Alexey Golyshin +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "board/irq.h" // irq_save +#include "board/misc.h" // timer_from_us +#include "command.h" // shutdown +#include "compiler.h" // ARRAY_SIZE +#include "generic/armcm_timer.h" // udelay +#include "gpio.h" // gpio_adc_setup +#include "internal.h" // GPIO +#include "sched.h" // sched_shutdown +#include "n32g45x_adc.h" // ADC + +DECL_CONSTANT("ADC_MAX", 4095); + +#define ADC_TEMPERATURE_PIN 0xfe +DECL_ENUMERATION("pin", "ADC_TEMPERATURE", ADC_TEMPERATURE_PIN); + +static const uint8_t adc_pins[] = { + // ADC1 + 0, GPIO('A', 0), GPIO('A', 1), GPIO('A', 6), + GPIO('A', 3), GPIO('F', 4), 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + ADC_TEMPERATURE_PIN, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + // ADC2 + 0, GPIO('A', 4), GPIO('A', 5), GPIO('B', 1), + GPIO('A', 7), GPIO('C', 4), GPIO('C', 0), GPIO('C', 1), + GPIO('C', 2), GPIO('C', 3), GPIO('F', 2), GPIO('A', 2), + GPIO('C', 5), GPIO('B', 2), 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, +#if CONFIG_MACH_N32G455 // ADC3/4 for G455 only + // ADC3 + 0, GPIO('B', 11), GPIO('E', 9), GPIO('E', 13), + GPIO('E', 12), GPIO('B', 13), GPIO('E', 8), GPIO('D', 10), + GPIO('D', 11), GPIO('D', 12), GPIO('D', 13), GPIO('D', 14), + GPIO('B', 0), GPIO('E', 7), GPIO('E', 10), GPIO('E', 11), + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + // ADC4 + 0, GPIO('E', 14), GPIO('E', 15), GPIO('B', 12), + GPIO('B', 14), GPIO('B', 15), 0, 0, + 0, 0, 0, 0, + GPIO('D', 8), GPIO('D', 9), 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, +#endif +}; + +// Perform calibration +static void +adc_calibrate(ADC_Module *adc) +{ + adc->CTRL2 = CTRL2_AD_ON_SET; + while (!(adc->CTRL3 & ADC_FLAG_RDY)) + ; + adc->CTRL3 &= (~ADC_CTRL3_BPCAL_MSK); + udelay(10); + adc->CTRL2 = CTRL2_AD_ON_SET | CTRL2_CAL_SET; + while (adc->CTRL2 & CTRL2_CAL_SET) + ; +} + +struct gpio_adc +gpio_adc_setup(uint32_t pin) +{ + // Find pin in adc_pins table + int chan; + for (chan=0; ; chan++) { + if (chan >= ARRAY_SIZE(adc_pins)) + shutdown("Not a valid ADC pin"); + if (adc_pins[chan] == pin) + break; + } + + // Determine which ADC block to use + ADC_Module *adc; + if ((chan >> 5) == 0) + adc = NS_ADC1; + if ((chan >> 5) == 1) + adc = NS_ADC2; + if ((chan >> 5) == 2) + adc = NS_ADC3; + if ((chan >> 5) == 3) + adc = NS_ADC4; + chan &= 0x1F; + + // Enable the ADC + uint32_t reg_temp; + reg_temp = ADC_RCC_AHBPCLKEN; + reg_temp |= (RCC_AHB_PERIPH_ADC1 | RCC_AHB_PERIPH_ADC2 | + RCC_AHB_PERIPH_ADC3 | RCC_AHB_PERIPH_ADC4); + ADC_RCC_AHBPCLKEN = reg_temp; + + reg_temp = ADC_RCC_CFG2; + reg_temp &= CFG2_ADCPLLPRES_RESET_MASK; + reg_temp |= RCC_ADCPLLCLK_DIV1; + reg_temp &= RCC_ADCPLLCLK_DISABLE; + ADC_RCC_CFG2 = reg_temp; + + reg_temp = ADC_RCC_CFG2; + reg_temp &= CFG2_ADCHPRES_RESET_MASK; + reg_temp |= RCC_ADCHCLK_DIV16; + ADC_RCC_CFG2 = reg_temp; + + ADC_InitType ADC_InitStructure; + ADC_InitStructure.WorkMode = ADC_WORKMODE_INDEPENDENT; + ADC_InitStructure.MultiChEn = 0; + ADC_InitStructure.ContinueConvEn = 0; + ADC_InitStructure.ExtTrigSelect = ADC_EXT_TRIGCONV_NONE; + ADC_InitStructure.DatAlign = ADC_DAT_ALIGN_R; + ADC_InitStructure.ChsNumber = 1; + ADC_Init(adc, &ADC_InitStructure); + + adc_calibrate(adc); + + if (pin == ADC_TEMPERATURE_PIN) { + NS_ADC1->CTRL2 |= CTRL2_TSVREFE_SET; + VREF1P2_CTRL |= (1<<10); + } else { + gpio_peripheral(pin, GPIO_ANALOG, 0); + } + + return (struct gpio_adc){ .adc = adc, .chan = chan }; +} + +// Try to sample a value. Returns zero if sample ready, otherwise +// returns the number of clock ticks the caller should wait before +// retrying this function. +uint32_t +gpio_adc_sample(struct gpio_adc g) +{ + ADC_Module *adc = g.adc; + uint32_t sr = adc->STS; + if (sr & ADC_STS_STR) { + if (!(sr & ADC_STS_ENDC) || adc->RSEQ3 != g.chan) + // Conversion still in progress or busy on another channel + goto need_delay; + // Conversion ready + return 0; + } + // ADC timing: clock=4Mhz, Tconv=12.5, Tsamp=41.5, total=13.500us + ADC_ConfigRegularChannel(adc, g.chan, 1, ADC_SAMP_TIME_41CYCLES5); + adc->CTRL2 |= CTRL2_AD_ON_SET; + adc->CTRL2 |= CTRL2_EXT_TRIG_SWSTART_SET; + +need_delay: + return timer_from_us(20); +} + +// Read a value; use only after gpio_adc_sample() returns zero +uint16_t +gpio_adc_read(struct gpio_adc g) +{ + ADC_Module *adc = g.adc; + adc->STS &= ~ADC_STS_ENDC; + adc->STS &= ~ADC_STS_STR; + adc->CTRL2 &= CTRL2_EXT_TRIG_SWSTART_RESET; + uint16_t result = adc->DAT; + return result; +} + +// Cancel a sample that may have been started with gpio_adc_sample() +void +gpio_adc_cancel_sample(struct gpio_adc g) +{ + ADC_Module *adc = g.adc; + irqstatus_t flag = irq_save(); + if (adc->STS & ADC_STS_STR) + gpio_adc_read(g); + irq_restore(flag); +} diff --git a/src/stm32/stm32f0_i2c.c b/src/stm32/stm32f0_i2c.c index a37306e8c3d8..48c3ae3e7747 100644 --- a/src/stm32/stm32f0_i2c.c +++ b/src/stm32/stm32f0_i2c.c @@ -72,6 +72,13 @@ struct i2c_info { DECL_CONSTANT_STR("BUS_PINS_i2c3_PC8_PC9", "PC8,PC9"); DECL_ENUMERATION("i2c_bus", "i2c3_PC8_PC11", 7); DECL_CONSTANT_STR("BUS_PINS_i2c3_PC8_PC11", "PC8,PC11"); +#elif CONFIG_MACH_STM32H7 + DECL_ENUMERATION("i2c_bus", "i2c1_PB6_PB7", 0); + DECL_CONSTANT_STR("BUS_PINS_i2c1_PB6_PB7", "PB6,PB7"); + DECL_ENUMERATION("i2c_bus", "i2c1_PB8_PB9", 1); + DECL_CONSTANT_STR("BUS_PINS_i2c1_PB8_PB9", "PB8,PB9"); + DECL_ENUMERATION("i2c_bus", "i2c2_PB10_PB11", 2); + DECL_CONSTANT_STR("BUS_PINS_i2c2_PB10_PB11", "PB10,PB11"); #endif static const struct i2c_info i2c_bus[] = { @@ -104,6 +111,10 @@ static const struct i2c_info i2c_bus[] = { { I2C2, GPIO('C', 4), GPIO('F', 0), GPIO_FUNCTION(4) }, { I2C3, GPIO('C', 8), GPIO('C', 9), GPIO_FUNCTION(8) }, { I2C3, GPIO('C', 8), GPIO('C', 11), GPIO_FUNCTION(8) }, +#elif CONFIG_MACH_STM32H7 + { I2C1, GPIO('B', 6), GPIO('B', 7), GPIO_FUNCTION(4) }, + { I2C1, GPIO('B', 8), GPIO('B', 9), GPIO_FUNCTION(4) }, + { I2C2, GPIO('B', 10), GPIO('B', 11), GPIO_FUNCTION(4) }, #endif }; diff --git a/src/stm32/stm32f0_serial.c b/src/stm32/stm32f0_serial.c index 4f6495f7ecb7..e48960f1163c 100644 --- a/src/stm32/stm32f0_serial.c +++ b/src/stm32/stm32f0_serial.c @@ -78,6 +78,13 @@ #define USARTx_FUNCTION GPIO_FUNCTION(8) #define USARTx UART4 #define USARTx_IRQn UART4_IRQn +#elif CONFIG_STM32_SERIAL_USART5 + DECL_CONSTANT_STR("RESERVE_PINS_serial", "PD2,PD3"); + #define GPIO_Rx GPIO('D', 2) + #define GPIO_Tx GPIO('D', 3) + #define USARTx_FUNCTION GPIO_FUNCTION(3) + #define USARTx USART5 + #define USARTx_IRQn USART5_IRQn #endif #if CONFIG_MACH_STM32F031 @@ -90,6 +97,10 @@ // Some of the stm32g0 MCUs have slightly different register names #if CONFIG_MACH_STM32G0B1 #define USART2_IRQn USART2_LPUART2_IRQn + #define USART3_IRQn USART3_4_5_6_LPUART1_IRQn + #define USART4_IRQn USART3_4_5_6_LPUART1_IRQn + #define USART5_IRQn USART3_4_5_6_LPUART1_IRQn + #define USART6_IRQn USART3_4_5_6_LPUART1_IRQn #endif #define USART_CR1_RXNEIE USART_CR1_RXNEIE_RXFNEIE #define USART_CR1_TXEIE USART_CR1_TXEIE_TXFNFIE diff --git a/src/stm32/stm32g0.c b/src/stm32/stm32g0.c index b96d4a517fd1..7408612ade2e 100644 --- a/src/stm32/stm32g0.c +++ b/src/stm32/stm32g0.c @@ -32,6 +32,14 @@ lookup_clock_line(uint32_t periph_base) uint32_t bit = 1 << ((periph_base - AHBPERIPH_BASE) / 0x400); return (struct cline){.en=&RCC->AHBENR, .rst=&RCC->AHBRSTR, .bit=bit}; } +#ifdef USART5_BASE + if (periph_base == USART5_BASE) + return (struct cline){.en=&RCC->APBENR1,.rst=&RCC->APBRSTR1,.bit=1<<8}; +#endif +#ifdef USART6_BASE + if (periph_base == USART6_BASE) + return (struct cline){.en=&RCC->APBENR1,.rst=&RCC->APBRSTR1,.bit=1<<9}; +#endif #if defined(FDCAN1_BASE) || defined(FDCAN2_BASE) if ((periph_base == FDCAN1_BASE) || (periph_base == FDCAN2_BASE)) return (struct cline){.en=&RCC->APBENR1,.rst=&RCC->APBRSTR1,.bit=1<<12}; diff --git a/src/stm32/usbfs.c b/src/stm32/usbfs.c index f7559efd6fa0..fda2ce9d299c 100644 --- a/src/stm32/usbfs.c +++ b/src/stm32/usbfs.c @@ -15,7 +15,7 @@ #include "internal.h" // GPIO #include "sched.h" // DECL_INIT -#if CONFIG_MACH_STM32F103 || CONFIG_MACH_STM32G4 +#if CONFIG_MACH_STM32F1 || CONFIG_MACH_STM32G4 // Transfer memory is accessed with 32bits, but contains only 16bits of data typedef volatile uint32_t epmword_t; #define WSIZE 2 diff --git a/src/stm32/usbotg.c b/src/stm32/usbotg.c index b61c99ca2959..7482925606e5 100644 --- a/src/stm32/usbotg.c +++ b/src/stm32/usbotg.c @@ -397,11 +397,11 @@ OTG_FS_IRQHandler(void) } if (sts & USB_OTG_GINTSTS_IEPINT) { // Can transmit data - disable irq and notify endpoint - uint32_t daint = OTGD->DAINT; - OTGD->DAINTMSK &= ~daint; - if (daint & (1 << 0)) + uint32_t daint = OTGD->DAINT, msk = OTGD->DAINTMSK, pend = daint & msk; + OTGD->DAINTMSK = msk & ~daint; + if (pend & (1 << 0)) usb_notify_ep0(); - if (daint & (1 << USB_CDC_EP_BULK_IN)) + if (pend & (1 << USB_CDC_EP_BULK_IN)) usb_notify_bulk_in(); } } diff --git a/test/klippy/printers.test b/test/klippy/printers.test index 75b0d7d960c0..7194eb46dc69 100644 --- a/test/klippy/printers.test +++ b/test/klippy/printers.test @@ -154,6 +154,7 @@ CONFIG ../../config/generic-bigtreetech-skr-mini-e3-v2.0.cfg CONFIG ../../config/generic-bigtreetech-skr-mini-mz.cfg CONFIG ../../config/printer-anycubic-vyper-2021.cfg CONFIG ../../config/printer-monoprice-select-mini-v1-2016.cfg +CONFIG ../../config/printer-sovol-sv05-2022.cfg CONFIG ../../config/printer-sovol-sv06-2022.cfg CONFIG ../../config/printer-sunlu-t3-2022.cfg @@ -195,6 +196,7 @@ CONFIG ../../config/printer-tronxy-xy-2-Pro-2020.cfg CONFIG ../../config/printer-twotrees-sapphire-plus-sp-5-v1-2020.cfg CONFIG ../../config/printer-twotrees-sapphire-plus-sp-5-v1.1-2021.cfg CONFIG ../../config/printer-twotrees-sapphire-pro-sp-3-2020.cfg +CONFIG ../../config/printer-voxelab-aquila-2021.cfg # Printers using the stm32f401 DICTIONARY stm32f401.dict @@ -229,6 +231,7 @@ CONFIG ../../config/generic-fysetc-s6.cfg CONFIG ../../config/generic-fysetc-s6-v2.cfg CONFIG ../../config/generic-fysetc-spider.cfg CONFIG ../../config/generic-mks-rumba32-v1.0.cfg +CONFIG ../../config/printer-ratrig-v-minion-2021.cfg # Printers using the stm32h723 DICTIONARY stm32h723.dict @@ -254,6 +257,7 @@ CONFIG ../../config/generic-bigtreetech-skr-pico-v1.0.cfg # Anycubic Printers using trigorilla board with the hc32f460 DICTIONARY hc32f460-serial-PA3PA2.dict +CONFIG ../../config/printer-anycubic-kobra-go-2022.cfg CONFIG ../../config/printer-anycubic-kobra-plus-2022.cfg # Printers using the PRU