Compare commits

...

11 Commits

Author SHA1 Message Date
23a7de4d02 Merge branch 'dev' 2022-10-08 19:50:30 +02:00
79ab4613f6 Merge branch '9-re-write-the-schematic-in-kicad' into 'dev'
Resolve "Re-write the schematic in Kicad"

See merge request Steins7/fan_monitor!9
2022-03-07 15:04:25 +00:00
d4c12cce25 Resolve "Re-write the schematic in Kicad" 2022-03-07 15:04:25 +00:00
70335c54be Merge branch '11-improve-calibration-display' into 'dev'
Resolve "Improve calibration display"

See merge request Steins7/fan_monitor!10
2022-01-29 14:55:58 +00:00
5d4035f98f Added offset to calibration display
+ added display of offset value
* renamed section to save space
2022-01-29 15:54:45 +01:00
7941ceeb51 Merge branch '8-implement-configuration-persistence' into 'dev'
Resolve "Implement configuration persistence"

See merge request Steins7/fan_monitor!5
2022-01-29 14:42:59 +00:00
dedb811aab Implemented config persitence
+ added ConfigStorage struct
+ added CRC computation for data integrity
* fixed config error message not showing
2022-01-29 15:41:05 +01:00
07245df732 Merge branch '10-system-is-starting-without-config' into 'dev'
Resolve "System is starting without config"

See merge request Steins7/fan_monitor!8
2022-01-28 10:32:04 +00:00
3fc3dbaae8 Added config error screen
+ added error management
+ added config error when failing to load
2022-01-25 14:09:16 +01:00
a3a2386dc2 Merge branch '7-design-new-gui' into 'dev'
Resolve "Design new GUI"

See merge request Steins7/fan_monitor!6
2022-01-07 07:45:37 +00:00
3668d9b80d Resolve "Design new GUI" 2022-01-07 07:45:37 +00:00
23 changed files with 31823 additions and 119 deletions

39
.gitignore vendored
View File

@ -1,6 +1,45 @@
#-------------------------------------------------------------------------------
# Rust
**/*.rs.bk **/*.rs.bk
.#* .#*
.gdb_history .gdb_history
Cargo.lock Cargo.lock
target/ target/
#-------------------------------------------------------------------------------
# For PCBs designed using KiCad: https://www.kicad.org/
# Format documentation: https://kicad.org/help/file-formats/
# Temporary files
*.000
*.bak
*.bck
*.kicad_pcb-bak
*.kicad_sch-bak
*-backups
*.kicad_prl
*.sch-bak
*~
_autosave-*
\#auto_saved_files\#
*.tmp
*-save.pro
*-save.kicad_pcb
fp-info-cache
# Netlist files (exported from Eeschema)
*.net
# Autorouter files (exported from Pcbnew)
*.dsn
*.ses
# Exported BOM files
*.xml
*.csv
#-------------------------------------------------------------------------------
# LibreOffice
*.~lock*

View File

@ -8,15 +8,16 @@ version = "0.1.0"
[dependencies] [dependencies]
embedded-hal = "0.2.6" embedded-hal = "0.2.6"
nb = "0.1.2" nb = "0.1.2"
cortex-m = "0.6.0" cortex-m = "0.7.4"
cortex-m-rt = "0.6.10" cortex-m-rt = "0.7.1"
cortex-m-semihosting = "0.3.3" cortex-m-semihosting = "0.3.7"
panic-halt = "0.2.0" panic-halt = "0.2.0"
hd44780-driver = "0.3.0" hd44780-driver = "0.3.0"
libm = "0.2.1" libm = "0.2.1"
half = "1.8.2"
[dependencies.stm32f1xx-hal] [dependencies.stm32f1xx-hal]
version = "0.7.0" version = "0.8.0"
features = ["stm32f103", "rt", "medium"] features = ["stm32f103", "rt", "medium"]
# this lets you use `cargo fix`! # this lets you use `cargo fix`!

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,484 @@
{
"board": {
"design_settings": {
"defaults": {
"board_outline_line_width": 0.09999999999999999,
"copper_line_width": 0.19999999999999998,
"copper_text_italic": false,
"copper_text_size_h": 1.5,
"copper_text_size_v": 1.5,
"copper_text_thickness": 0.3,
"copper_text_upright": false,
"courtyard_line_width": 0.049999999999999996,
"dimension_precision": 4,
"dimension_units": 3,
"dimensions": {
"arrow_length": 1270000,
"extension_offset": 500000,
"keep_text_aligned": true,
"suppress_zeroes": false,
"text_position": 0,
"units_format": 1
},
"fab_line_width": 0.09999999999999999,
"fab_text_italic": false,
"fab_text_size_h": 1.0,
"fab_text_size_v": 1.0,
"fab_text_thickness": 0.15,
"fab_text_upright": false,
"other_line_width": 0.15,
"other_text_italic": false,
"other_text_size_h": 1.0,
"other_text_size_v": 1.0,
"other_text_thickness": 0.15,
"other_text_upright": false,
"pads": {
"drill": 3.2,
"height": 5.6,
"width": 5.6
},
"silk_line_width": 0.15,
"silk_text_italic": false,
"silk_text_size_h": 1.0,
"silk_text_size_v": 1.0,
"silk_text_thickness": 0.15,
"silk_text_upright": false,
"zones": {
"45_degree_only": false,
"min_clearance": 0.508
}
},
"diff_pair_dimensions": [
{
"gap": 0.0,
"via_gap": 0.0,
"width": 0.0
}
],
"drc_exclusions": [],
"meta": {
"version": 2
},
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"copper_edge_clearance": "error",
"courtyards_overlap": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint_type_mismatch": "error",
"hole_clearance": "error",
"hole_near_hole": "error",
"invalid_outline": "error",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"malformed_courtyard": "ignore",
"microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore",
"missing_footprint": "warning",
"net_conflict": "warning",
"npth_inside_courtyard": "ignore",
"padstack": "error",
"pth_inside_courtyard": "ignore",
"shorting_items": "error",
"silk_over_copper": "ignore",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_dangling": "warning",
"track_width": "error",
"tracks_crossing": "error",
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
"zone_has_empty_net": "error",
"zones_intersect": "error"
},
"rules": {
"allow_blind_buried_vias": false,
"allow_microvias": false,
"max_error": 0.005,
"min_clearance": 0.0,
"min_copper_edge_clearance": 0.0,
"min_hole_clearance": 0.25,
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.19999999999999998,
"min_microvia_drill": 0.09999999999999999,
"min_silk_clearance": 0.0,
"min_through_hole_diameter": 0.3,
"min_track_width": 0.15,
"min_via_annular_width": 0.049999999999999996,
"min_via_diameter": 0.39999999999999997,
"solder_mask_clearance": 0.0,
"solder_mask_min_width": 0.0,
"use_height_for_length_calcs": true
},
"track_widths": [
0.0,
0.5,
0.8
],
"via_dimensions": [
{
"diameter": 0.0,
"drill": 0.0
},
{
"diameter": 0.6,
"drill": 0.3
},
{
"diameter": 0.9,
"drill": 0.6
}
],
"zones_allow_external_fillets": false,
"zones_use_no_outline": true
},
"layer_presets": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_label_syntax": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"extra_units": "error",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"lib_symbol_issues": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
"no_connect_dangling": "warning",
"pin_not_connected": "error",
"pin_not_driven": "error",
"pin_to_pin": "warning",
"power_pin_not_driven": "error",
"similar_labels": "warning",
"unannotated": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
}
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "fan_monitor.kicad_pro",
"version": 1
},
"net_settings": {
"classes": [
{
"bus_width": 12.0,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "Default",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.5,
"via_diameter": 0.6,
"via_drill": 0.35,
"wire_width": 6.0
},
{
"bus_width": 12.0,
"clearance": 2.4,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "380AC",
"nets": [
"Net-(F1-Pad1)",
"Net-(F1-Pad2)"
],
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.8,
"via_diameter": 0.9,
"via_drill": 0.6,
"wire_width": 6.0
},
{
"bus_width": 12.0,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "5V_main",
"nets": [
"Net-(J4-Pad1)"
],
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.8,
"via_diameter": 0.6,
"via_drill": 0.35,
"wire_width": 6.0
}
],
"meta": {
"version": 2
},
"net_colors": null
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"specctra_dsn": "",
"step": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"drawing": {
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.375,
"pin_symbol_size": 25.0,
"text_offset_ratio": 0.15
},
"legacy_lib_dir": "",
"legacy_lib_list": [],
"meta": {
"version": 1
},
"net_format_name": "",
"ngspice": {
"fix_include_paths": true,
"fix_passive_vals": false,
"meta": {
"version": 0
},
"model_mode": 0,
"workbook_filename": ""
},
"page_layout_descr_file": "",
"plot_directory": "",
"spice_adjust_passive_values": false,
"spice_external_command": "spice \"%I\"",
"subpart_first_id": 65,
"subpart_id_separator": 0
},
"sheets": [
[
"6475547d-3216-45a4-a15c-48314f1dd0f9",
""
]
],
"text_variables": {}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,638 @@
(kicad_symbol_lib (version 20211014) (generator kicad_symbol_editor)
(symbol "1SS315" (pin_numbers hide) (pin_names (offset 1.016) hide) (in_bom yes) (on_board yes)
(property "Reference" "D" (id 0) (at 0 2.54 0)
(effects (font (size 1.27 1.27)))
)
(property "Value" "1SS315" (id 1) (at 0 -2.54 0)
(effects (font (size 1.27 1.27)))
)
(property "Footprint" "Diode_SMD:D_SOD-323_HandSoldering" (id 2) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (id 3) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_keywords" "diode CMS SOD-323" (id 4) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_description" "Diode CMS Toshiba, 30mA, 5V, SOD-323" (id 5) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_fp_filters" "TO-???* *_Diode_* *SingleDiode* D_*" (id 6) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(symbol "1SS315_0_1"
(polyline
(pts
(xy -1.27 1.27)
(xy -1.27 -1.27)
)
(stroke (width 0.254) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 1.27 0)
(xy -1.27 0)
)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 1.27 1.27)
(xy 1.27 -1.27)
(xy -1.27 0)
(xy 1.27 1.27)
)
(stroke (width 0.254) (type default) (color 0 0 0 0))
(fill (type none))
)
)
(symbol "1SS315_1_1"
(pin passive line (at -3.81 0 0) (length 2.54)
(name "K" (effects (font (size 1.27 1.27))))
(number "1" (effects (font (size 1.27 1.27))))
)
(pin passive line (at 3.81 0 180) (length 2.54)
(name "A" (effects (font (size 1.27 1.27))))
(number "2" (effects (font (size 1.27 1.27))))
)
)
)
(symbol "2N4401" (pin_names (offset 0) hide) (in_bom yes) (on_board yes)
(property "Reference" "Q" (id 0) (at 5.08 1.905 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Value" "2N4401" (id 1) (at 5.08 0 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Footprint" "Package_TO_SOT_THT:TO-92_Inline" (id 2) (at 5.08 -1.905 0)
(effects (font (size 1.27 1.27) italic) (justify left) hide)
)
(property "Datasheet" "https://www.onsemi.com/pub/Collateral/2N3903-D.PDF" (id 3) (at 0 0 0)
(effects (font (size 1.27 1.27)) (justify left) hide)
)
(property "ki_keywords" "NPN Transistor" (id 4) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_description" "0.2A Ic, 40V Vce, Small Signal NPN Transistor, TO-92" (id 5) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_fp_filters" "TO?92*" (id 6) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(symbol "2N4401_0_1"
(polyline
(pts
(xy 0.635 0.635)
(xy 2.54 2.54)
)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 0.635 -0.635)
(xy 2.54 -2.54)
(xy 2.54 -2.54)
)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 0.635 1.905)
(xy 0.635 -1.905)
(xy 0.635 -1.905)
)
(stroke (width 0.508) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 1.27 -1.778)
(xy 1.778 -1.27)
(xy 2.286 -2.286)
(xy 1.27 -1.778)
(xy 1.27 -1.778)
)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type outline))
)
(circle (center 1.27 0) (radius 2.8194)
(stroke (width 0.254) (type default) (color 0 0 0 0))
(fill (type none))
)
)
(symbol "2N4401_1_1"
(pin passive line (at 2.54 -5.08 90) (length 2.54)
(name "E" (effects (font (size 1.27 1.27))))
(number "1" (effects (font (size 1.27 1.27))))
)
(pin passive line (at -5.08 0 0) (length 5.715)
(name "B" (effects (font (size 1.27 1.27))))
(number "2" (effects (font (size 1.27 1.27))))
)
(pin passive line (at 2.54 5.08 270) (length 2.54)
(name "C" (effects (font (size 1.27 1.27))))
(number "3" (effects (font (size 1.27 1.27))))
)
)
)
(symbol "HE10-16" (pin_names (offset 1.016) hide) (in_bom yes) (on_board yes)
(property "Reference" "J" (id 0) (at 1.27 10.16 0)
(effects (font (size 1.27 1.27)))
)
(property "Value" "HE10-16" (id 1) (at 1.27 -12.7 0)
(effects (font (size 1.27 1.27)))
)
(property "Footprint" "" (id 2) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (id 3) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_keywords" "connector" (id 4) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_description" "Generic connector, double row, 02x08, odd/even pin numbering scheme (row 1 odd numbers, row 2 even numbers), script generated (kicad-library-utils/schlib/autogen/connector/)" (id 5) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_fp_filters" "Connector*:*_2x??_*" (id 6) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(symbol "HE10-16_1_1"
(rectangle (start -1.27 -10.033) (end 0 -10.287)
(stroke (width 0.1524) (type default) (color 0 0 0 0))
(fill (type none))
)
(rectangle (start -1.27 -7.493) (end 0 -7.747)
(stroke (width 0.1524) (type default) (color 0 0 0 0))
(fill (type none))
)
(rectangle (start -1.27 -4.953) (end 0 -5.207)
(stroke (width 0.1524) (type default) (color 0 0 0 0))
(fill (type none))
)
(rectangle (start -1.27 -2.413) (end 0 -2.667)
(stroke (width 0.1524) (type default) (color 0 0 0 0))
(fill (type none))
)
(rectangle (start -1.27 0.127) (end 0 -0.127)
(stroke (width 0.1524) (type default) (color 0 0 0 0))
(fill (type none))
)
(rectangle (start -1.27 2.667) (end 0 2.413)
(stroke (width 0.1524) (type default) (color 0 0 0 0))
(fill (type none))
)
(rectangle (start -1.27 5.207) (end 0 4.953)
(stroke (width 0.1524) (type default) (color 0 0 0 0))
(fill (type none))
)
(rectangle (start -1.27 7.747) (end 0 7.493)
(stroke (width 0.1524) (type default) (color 0 0 0 0))
(fill (type none))
)
(rectangle (start -1.27 8.89) (end 3.81 -11.43)
(stroke (width 0.254) (type default) (color 0 0 0 0))
(fill (type background))
)
(rectangle (start 3.81 -10.033) (end 2.54 -10.287)
(stroke (width 0.1524) (type default) (color 0 0 0 0))
(fill (type none))
)
(rectangle (start 3.81 -7.493) (end 2.54 -7.747)
(stroke (width 0.1524) (type default) (color 0 0 0 0))
(fill (type none))
)
(rectangle (start 3.81 -4.953) (end 2.54 -5.207)
(stroke (width 0.1524) (type default) (color 0 0 0 0))
(fill (type none))
)
(rectangle (start 3.81 -2.413) (end 2.54 -2.667)
(stroke (width 0.1524) (type default) (color 0 0 0 0))
(fill (type none))
)
(rectangle (start 3.81 0.127) (end 2.54 -0.127)
(stroke (width 0.1524) (type default) (color 0 0 0 0))
(fill (type none))
)
(rectangle (start 3.81 2.667) (end 2.54 2.413)
(stroke (width 0.1524) (type default) (color 0 0 0 0))
(fill (type none))
)
(rectangle (start 3.81 5.207) (end 2.54 4.953)
(stroke (width 0.1524) (type default) (color 0 0 0 0))
(fill (type none))
)
(rectangle (start 3.81 7.747) (end 2.54 7.493)
(stroke (width 0.1524) (type default) (color 0 0 0 0))
(fill (type none))
)
(pin passive line (at -5.08 7.62 0) (length 3.81)
(name "Pin_1" (effects (font (size 1.27 1.27))))
(number "1" (effects (font (size 1.27 1.27))))
)
(pin passive line (at 7.62 -2.54 180) (length 3.81)
(name "Pin_10" (effects (font (size 1.27 1.27))))
(number "10" (effects (font (size 1.27 1.27))))
)
(pin passive line (at -5.08 -5.08 0) (length 3.81)
(name "Pin_11" (effects (font (size 1.27 1.27))))
(number "11" (effects (font (size 1.27 1.27))))
)
(pin passive line (at 7.62 -5.08 180) (length 3.81)
(name "Pin_12" (effects (font (size 1.27 1.27))))
(number "12" (effects (font (size 1.27 1.27))))
)
(pin passive line (at -5.08 -7.62 0) (length 3.81)
(name "Pin_13" (effects (font (size 1.27 1.27))))
(number "13" (effects (font (size 1.27 1.27))))
)
(pin passive line (at 7.62 -7.62 180) (length 3.81)
(name "Pin_14" (effects (font (size 1.27 1.27))))
(number "14" (effects (font (size 1.27 1.27))))
)
(pin passive line (at -5.08 -10.16 0) (length 3.81)
(name "Pin_15" (effects (font (size 1.27 1.27))))
(number "15" (effects (font (size 1.27 1.27))))
)
(pin passive line (at 7.62 -10.16 180) (length 3.81)
(name "Pin_16" (effects (font (size 1.27 1.27))))
(number "16" (effects (font (size 1.27 1.27))))
)
(pin passive line (at 7.62 7.62 180) (length 3.81)
(name "Pin_2" (effects (font (size 1.27 1.27))))
(number "2" (effects (font (size 1.27 1.27))))
)
(pin passive line (at -5.08 5.08 0) (length 3.81)
(name "Pin_3" (effects (font (size 1.27 1.27))))
(number "3" (effects (font (size 1.27 1.27))))
)
(pin passive line (at 7.62 5.08 180) (length 3.81)
(name "Pin_4" (effects (font (size 1.27 1.27))))
(number "4" (effects (font (size 1.27 1.27))))
)
(pin passive line (at -5.08 2.54 0) (length 3.81)
(name "Pin_5" (effects (font (size 1.27 1.27))))
(number "5" (effects (font (size 1.27 1.27))))
)
(pin passive line (at 7.62 2.54 180) (length 3.81)
(name "Pin_6" (effects (font (size 1.27 1.27))))
(number "6" (effects (font (size 1.27 1.27))))
)
(pin passive line (at -5.08 0 0) (length 3.81)
(name "Pin_7" (effects (font (size 1.27 1.27))))
(number "7" (effects (font (size 1.27 1.27))))
)
(pin passive line (at 7.62 0 180) (length 3.81)
(name "Pin_8" (effects (font (size 1.27 1.27))))
(number "8" (effects (font (size 1.27 1.27))))
)
(pin passive line (at -5.08 -2.54 0) (length 3.81)
(name "Pin_9" (effects (font (size 1.27 1.27))))
(number "9" (effects (font (size 1.27 1.27))))
)
)
)
(symbol "HF152FD{slash}5-1H" (in_bom yes) (on_board yes)
(property "Reference" "K" (id 0) (at 11.43 3.81 0)
(effects (font (size 1.27 1.27)))
)
(property "Value" "HF152FD{slash}5-1H" (id 1) (at 18.415 1.27 0)
(effects (font (size 1.27 1.27)))
)
(property "Footprint" "fan_monitor:HF152FD_Form_A" (id 2) (at 33.655 -1.27 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "" (id 3) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_keywords" "SPST 1P1T" (id 4) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_description" "Hongfa, Small Non-Latching Power Relay, Single coil, 400VAC, 1 Form A" (id 5) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "ki_fp_filters" "Relay*1P1T*NO*Panasonic*ADW11xxxxW*" (id 6) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(symbol "HF152FD{slash}5-1H_0_0"
(text "?" (at -3.81 3.175 0)
(effects (font (size 1.27 1.27)))
)
)
(symbol "HF152FD{slash}5-1H_1_1"
(rectangle (start -10.16 5.08) (end 10.16 -5.08)
(stroke (width 0.254) (type default) (color 0 0 0 0))
(fill (type background))
)
(rectangle (start -8.255 1.905) (end -1.905 -1.905)
(stroke (width 0.254) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy -7.62 -1.905)
(xy -2.54 1.905)
)
(stroke (width 0.254) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy -5.08 -5.08)
(xy -5.08 -1.905)
)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy -5.08 5.08)
(xy -5.08 1.905)
)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy -1.905 0)
(xy -1.27 0)
)
(stroke (width 0.254) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy -0.635 0)
(xy 0 0)
)
(stroke (width 0.254) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 0.635 0)
(xy 1.27 0)
)
(stroke (width 0.254) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 0.635 0)
(xy 1.27 0)
)
(stroke (width 0.254) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 1.905 0)
(xy 2.54 0)
)
(stroke (width 0.254) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 3.175 0)
(xy 3.81 0)
)
(stroke (width 0.254) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 5.08 -2.54)
(xy 3.175 3.81)
)
(stroke (width 0.508) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 5.08 -2.54)
(xy 5.08 -5.08)
)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 7.62 3.81)
(xy 7.62 5.08)
)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type none))
)
(polyline
(pts
(xy 7.62 3.81)
(xy 7.62 2.54)
(xy 6.985 3.175)
(xy 7.62 3.81)
)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type none))
)
(pin passive line (at -5.08 7.62 270) (length 2.54)
(name "~" (effects (font (size 1.27 1.27))))
(number "1" (effects (font (size 1.27 1.27))))
)
(pin passive line (at -5.08 -7.62 90) (length 2.54)
(name "~" (effects (font (size 1.27 1.27))))
(number "2" (effects (font (size 1.27 1.27))))
)
(pin passive line (at 5.08 -7.62 90) (length 2.54)
(name "~" (effects (font (size 1.27 1.27))))
(number "3" (effects (font (size 1.27 1.27))))
)
(pin passive line (at 7.62 7.62 270) (length 2.54)
(name "~" (effects (font (size 1.27 1.27))))
(number "4" (effects (font (size 1.27 1.27))))
)
)
)
(symbol "blue_pill" (pin_names (offset 1.016)) (in_bom yes) (on_board yes)
(property "Reference" "U" (id 0) (at -12.7 22.86 0)
(effects (font (size 1.524 1.524)))
)
(property "Value" "blue_pill" (id 1) (at 7.62 -24.13 0)
(effects (font (size 1.524 1.524)))
)
(property "Footprint" "Module:blue_pill" (id 2) (at -2.54 19.05 0)
(effects (font (size 1.524 1.524)) hide)
)
(property "Datasheet" "https://www.electronicshub.org/getting-started-with-stm32f103c8t6-blue-pill/" (id 3) (at -2.54 19.05 0)
(effects (font (size 1.524 1.524)) hide)
)
(symbol "blue_pill_0_1"
(rectangle (start -13.97 21.59) (end 13.97 -21.59)
(stroke (width 0) (type default) (color 0 0 0 0))
(fill (type none))
)
)
(symbol "blue_pill_1_1"
(pin power_out line (at 0 26.67 270) (length 5.08)
(name "3.3V" (effects (font (size 1.27 1.27))))
(number "3V3" (effects (font (size 1.27 1.27))))
)
(pin power_out line (at 3.81 26.67 270) (length 5.08)
(name "5V" (effects (font (size 1.27 1.27))))
(number "5V" (effects (font (size 1.27 1.27))))
)
(pin input line (at -3.81 -26.67 90) (length 5.08)
(name "BOOT0" (effects (font (size 1.27 1.27))))
(number "BOOT" (effects (font (size 1.27 1.27))))
)
(pin power_out line (at 3.81 -26.67 90) (length 5.08)
(name "GND" (effects (font (size 1.27 1.27))))
(number "G" (effects (font (size 1.27 1.27))))
)
(pin input line (at -19.05 -20.32 0) (length 5.08)
(name "RESET" (effects (font (size 1.27 1.27))))
(number "NRST" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at -19.05 12.7 0) (length 5.08)
(name "PA0" (effects (font (size 1.27 1.27))))
(number "PA0" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at -19.05 10.16 0) (length 5.08)
(name "PA1" (effects (font (size 1.27 1.27))))
(number "PA1" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 19.05 -5.08 180) (length 5.08)
(name "PA10" (effects (font (size 1.27 1.27))))
(number "PA10" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 19.05 -2.54 180) (length 5.08)
(name "PA11" (effects (font (size 1.27 1.27))))
(number "PA11" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 19.05 0 180) (length 5.08)
(name "PA12" (effects (font (size 1.27 1.27))))
(number "PA12" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 19.05 2.54 180) (length 5.08)
(name "PA15" (effects (font (size 1.27 1.27))))
(number "PA15" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at -19.05 7.62 0) (length 5.08)
(name "PA2" (effects (font (size 1.27 1.27))))
(number "PA2" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at -19.05 5.08 0) (length 5.08)
(name "PA3" (effects (font (size 1.27 1.27))))
(number "PA3" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at -19.05 2.54 0) (length 5.08)
(name "PA4" (effects (font (size 1.27 1.27))))
(number "PA4" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at -19.05 0 0) (length 5.08)
(name "PA5" (effects (font (size 1.27 1.27))))
(number "PA5" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at -19.05 -2.54 0) (length 5.08)
(name "PA6" (effects (font (size 1.27 1.27))))
(number "PA6" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at -19.05 -5.08 0) (length 5.08)
(name "PA7" (effects (font (size 1.27 1.27))))
(number "PA7" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 19.05 -10.16 180) (length 5.08)
(name "PA8" (effects (font (size 1.27 1.27))))
(number "PA8" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 19.05 -7.62 180) (length 5.08)
(name "PA9" (effects (font (size 1.27 1.27))))
(number "PA9" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at -19.05 -7.62 0) (length 5.08)
(name "PB0" (effects (font (size 1.27 1.27))))
(number "PB0" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at -19.05 -10.16 0) (length 5.08)
(name "PB1" (effects (font (size 1.27 1.27))))
(number "PB1" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at -19.05 -12.7 0) (length 5.08)
(name "PB10" (effects (font (size 1.27 1.27))))
(number "PB10" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at -19.05 -15.24 0) (length 5.08)
(name "PB11" (effects (font (size 1.27 1.27))))
(number "PB11" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 19.05 -20.32 180) (length 5.08)
(name "PB12" (effects (font (size 1.27 1.27))))
(number "PB12" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 19.05 -17.78 180) (length 5.08)
(name "PB13" (effects (font (size 1.27 1.27))))
(number "PB13" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 19.05 -15.24 180) (length 5.08)
(name "PB14" (effects (font (size 1.27 1.27))))
(number "PB14" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 19.05 -12.7 180) (length 5.08)
(name "PB15" (effects (font (size 1.27 1.27))))
(number "PB15" (effects (font (size 1.27 1.27))))
)
(pin input line (at -1.27 -26.67 90) (length 5.08)
(name "BOOT1" (effects (font (size 1.27 1.27))))
(number "PB2" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 19.05 5.08 180) (length 5.08)
(name "PB3" (effects (font (size 1.27 1.27))))
(number "PB3" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 19.05 7.62 180) (length 5.08)
(name "PB4" (effects (font (size 1.27 1.27))))
(number "PB4" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 19.05 10.16 180) (length 5.08)
(name "PB5" (effects (font (size 1.27 1.27))))
(number "PB5" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 19.05 12.7 180) (length 5.08)
(name "PB6" (effects (font (size 1.27 1.27))))
(number "PB6" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 19.05 15.24 180) (length 5.08)
(name "PB7" (effects (font (size 1.27 1.27))))
(number "PB7" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 19.05 17.78 180) (length 5.08)
(name "PB8" (effects (font (size 1.27 1.27))))
(number "PB8" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 19.05 20.32 180) (length 5.08)
(name "PB9" (effects (font (size 1.27 1.27))))
(number "PB9" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at -19.05 20.32 0) (length 5.08)
(name "PC13" (effects (font (size 1.27 1.27))))
(number "PC13" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at -19.05 17.78 0) (length 5.08)
(name "PC14" (effects (font (size 1.27 1.27))))
(number "PC14" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at -19.05 15.24 0) (length 5.08)
(name "PC15" (effects (font (size 1.27 1.27))))
(number "PC15" (effects (font (size 1.27 1.27))))
)
(pin power_in line (at -3.81 26.67 270) (length 5.08)
(name "Vbat" (effects (font (size 1.27 1.27))))
(number "VBAT" (effects (font (size 1.27 1.27))))
)
)
)
)

View File

@ -0,0 +1,29 @@
(footprint "CR2032_Holder" (version 20211014) (generator pcbnew)
(layer "F.Cu")
(tedit 62261CA8)
(descr "Coin Cell PV Battery Holder")
(tags "CR2032")
(attr through_hole)
(fp_text reference "REF**" (at 7.3 -6.2 unlocked) (layer "F.SilkS")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp 23c65112-425a-4ada-b1ca-3a5e5f538f08)
)
(fp_text value "CR2032_Battery_Holder" (at 7.3 -4.7 unlocked) (layer "F.Fab")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp 4ef94bb9-2e0a-4fb6-a2da-03965e6f684d)
)
(fp_text user "${REFERENCE}" (at 7.3 -3.2 unlocked) (layer "F.Fab")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp 65867e2e-3f24-4116-aeeb-b7c0d0114cc2)
)
(fp_line (start 2.54 -2.54) (end -1.7 -2.54) (layer "F.SilkS") (width 0.12) (tstamp 476b1128-2a06-4418-8c4e-6e9ca4d7e5b7))
(fp_line (start 2.54 2.54) (end 2.54 -2.54) (layer "F.SilkS") (width 0.12) (tstamp 533854f6-ac37-46ef-b665-ba2d8aac1c93))
(fp_line (start -1.7 2.54) (end 2.54 2.54) (layer "F.SilkS") (width 0.12) (tstamp b2600e4c-aec5-41d4-a697-836066376dce))
(fp_circle (center -15.38 0) (end -1.5 0) (layer "F.SilkS") (width 0.12) (fill none) (tstamp 5b0557b9-b3ad-49ce-b3bc-d9e1ab30942e))
(fp_line (start 3.4 3.4) (end 3.4 -3.4) (layer "F.CrtYd") (width 0.1) (tstamp 07d95c75-cc60-460d-8e32-ab4c50dd8b25))
(fp_line (start -0.82 3.4) (end 3.4 3.4) (layer "F.CrtYd") (width 0.1) (tstamp 21b8ac40-eadf-4191-b4e4-7b4932f275a8))
(fp_line (start 3.4 -3.4) (end -0.82 -3.4) (layer "F.CrtYd") (width 0.1) (tstamp 9add2b14-349f-4255-8bc9-6867c4ac3e1c))
(fp_circle (center -15.38 0) (end -0.5 0) (layer "F.CrtYd") (width 0.1) (fill none) (tstamp 9e528cce-46ff-4bf2-83ab-a1ec37fb2e1f))
(pad "1" thru_hole circle (at 0 0) (size 2 2) (drill oval 1.3 1.2) (layers *.Cu *.Mask) (tstamp 48d89f06-d1fb-4760-981e-831543f25182))
(pad "2" thru_hole circle (at -20.49 0) (size 2 2) (drill 1.3) (layers *.Cu *.Mask) (tstamp 04216d84-e824-4bb3-b463-ea6199a58c8c))
)

View File

@ -0,0 +1,42 @@
(footprint "HE10-16" (version 20211014) (generator pcbnew)
(layer "F.Cu")
(tedit 62261CF8)
(descr "HE10-16 straight connector")
(tags "CONN HE10")
(attr through_hole)
(fp_text reference "HE10-16" (at -5.588 -6.096) (layer "F.SilkS")
(effects (font (size 1.778 1.778) (thickness 0.3048)))
(tstamp 89ef1cf6-a73d-4c50-90d3-6c27b7f0cb41)
)
(fp_text value "Val**" (at 12.7 6.096) (layer "F.SilkS")
(effects (font (size 1.778 1.778) (thickness 0.3048)))
(tstamp 0c0726bc-34f3-42e8-9a5f-0ffe16108e71)
)
(fp_line (start -12.7 -3.556) (end 12.7 -3.556) (layer "F.SilkS") (width 0.12) (tstamp 003a5141-e200-4e63-b032-3dc8d3c60607))
(fp_line (start -2.54 3.556) (end -12.7 3.556) (layer "F.SilkS") (width 0.12) (tstamp 092f439c-150d-415b-8b93-adf5f43b88bb))
(fp_line (start 12.7 3.556) (end 2.54 3.556) (layer "F.SilkS") (width 0.12) (tstamp 11338925-1d78-44eb-8945-bafb4bea6979))
(fp_line (start -11.684 0.508) (end -11.684 2.032) (layer "F.SilkS") (width 0.3048) (tstamp 48016a16-8602-46dd-bd85-d3687867709e))
(fp_line (start -2.54 4.318) (end 2.54 4.318) (layer "F.SilkS") (width 0.12) (tstamp 5a96ec7d-775a-4197-bd3a-b35afffc8167))
(fp_line (start -12.7 3.556) (end -12.7 -3.556) (layer "F.SilkS") (width 0.12) (tstamp 62572e48-123e-40e3-bbac-e4ee3d41f626))
(fp_line (start 12.7 -3.556) (end 12.7 3.556) (layer "F.SilkS") (width 0.12) (tstamp 6c09dd4e-4b6b-4d6d-bc2f-6d45b2513087))
(fp_line (start 2.54 3.556) (end 2.54 4.318) (layer "F.SilkS") (width 0.12) (tstamp 8ffd1010-e240-4259-9498-37bf8e52f29e))
(fp_line (start -2.54 4.318) (end -2.54 3.556) (layer "F.SilkS") (width 0.12) (tstamp c62d4278-6b5d-4e14-a6ad-d17662e7c6cc))
(fp_line (start -10.414 1.27) (end -11.684 0.508) (layer "F.SilkS") (width 0.3048) (tstamp e02cc154-2e4b-4cc3-94d2-75105d00954f))
(fp_line (start -11.684 2.032) (end -10.414 1.27) (layer "F.SilkS") (width 0.3048) (tstamp e9b94cbb-b6a7-43f9-a9af-38d866bd1cb6))
(pad "1" thru_hole circle (at -8.89 1.27) (size 1.524 1.524) (drill 0.9144) (layers *.Cu *.Mask) (tstamp 754700b8-82bc-4d0e-926c-196988658878))
(pad "2" thru_hole circle (at -8.89 -1.27) (size 1.524 1.524) (drill 0.9144) (layers *.Cu *.Mask) (tstamp 57c102eb-b177-4220-ac3e-15a5da0e4ef6))
(pad "3" thru_hole circle (at -6.35 1.27) (size 1.524 1.524) (drill 0.9144) (layers *.Cu *.Mask) (tstamp 8f7a1c62-e866-4146-b861-025badda20d3))
(pad "4" thru_hole circle (at -6.35 -1.27) (size 1.524 1.524) (drill 0.9144) (layers *.Cu *.Mask) (tstamp 2b71dc2a-4c96-42a0-bd46-95937452e3f3))
(pad "5" thru_hole circle (at -3.81 1.27) (size 1.524 1.524) (drill 0.9144) (layers *.Cu *.Mask) (tstamp 9bc1f9b0-8c47-431f-99ec-8a9b89e7b1d6))
(pad "6" thru_hole circle (at -3.81 -1.27) (size 1.524 1.524) (drill 0.9144) (layers *.Cu *.Mask) (tstamp 439749f2-96d3-44a8-bdc0-e4c1c8bbc1ad))
(pad "7" thru_hole circle (at -1.27 1.27) (size 1.524 1.524) (drill 0.9144) (layers *.Cu *.Mask) (tstamp c39b5135-fbe0-4931-ad80-ed9c1070d5dd))
(pad "8" thru_hole circle (at -1.27 -1.27) (size 1.524 1.524) (drill 0.9144) (layers *.Cu *.Mask) (tstamp a15870b4-20f7-4f81-83ab-93da37c2d447))
(pad "9" thru_hole circle (at 1.27 1.27) (size 1.524 1.524) (drill 0.9144) (layers *.Cu *.Mask) (tstamp 003ad17d-831b-4d0b-96cd-c4dc99e2314f))
(pad "10" thru_hole circle (at 1.27 -1.27) (size 1.524 1.524) (drill 0.9144) (layers *.Cu *.Mask) (tstamp 79d5e4ae-1bbc-4f06-959e-391f5b194e0e))
(pad "11" thru_hole circle (at 3.81 1.27) (size 1.524 1.524) (drill 0.9144) (layers *.Cu *.Mask) (tstamp a4523af0-9cc4-4355-96d1-c401269d0754))
(pad "12" thru_hole circle (at 3.81 -1.27) (size 1.524 1.524) (drill 0.9144) (layers *.Cu *.Mask) (tstamp 8ee69a29-e666-41b5-8ae6-a4a1a8687d7c))
(pad "13" thru_hole circle (at 6.35 1.27) (size 1.524 1.524) (drill 0.9144) (layers *.Cu *.Mask) (tstamp 6d37ba34-3704-4806-86e1-7fae824ef21b))
(pad "14" thru_hole circle (at 6.35 -1.27) (size 1.524 1.524) (drill 0.9144) (layers *.Cu *.Mask) (tstamp 20f6e38c-67a5-4644-b9a7-6ec89b3b64fd))
(pad "15" thru_hole circle (at 8.89 1.27) (size 1.524 1.524) (drill 0.9144) (layers *.Cu *.Mask) (tstamp 92c15745-902a-4afa-9c24-dd3fb8f004e2))
(pad "16" thru_hole circle (at 8.89 -1.27) (size 1.524 1.524) (drill 0.9144) (layers *.Cu *.Mask) (tstamp 59147bef-e7d3-42c9-9796-6326ea61071b))
)

View File

@ -0,0 +1,25 @@
(footprint "HF152FD_Form_A" (version 20211014) (generator pcbnew)
(layer "F.Cu")
(tedit 62261D25)
(attr through_hole)
(fp_text reference "REF**" (at 6 -5.5 unlocked) (layer "F.SilkS")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp 801b2c57-3824-49e5-89e3-7099dacfe6d1)
)
(fp_text value "HF152FD_Form_A" (at 6.4 -3.7 unlocked) (layer "F.Fab")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp 208846ef-9d16-4aea-8884-4ad489287be5)
)
(fp_line (start 17 13.9) (end 17 -2) (layer "F.SilkS") (width 0.12) (tstamp 049a0d59-31c4-4e8e-8965-d3040279d0ae))
(fp_line (start 12.2 6.15) (end 12.2 10.85) (layer "F.SilkS") (width 0.12) (tstamp 20b31638-a6e0-490f-9160-2d6a76791db0))
(fp_line (start -0.8 6) (end 8.1 6) (layer "F.SilkS") (width 0.12) (tstamp a577a535-624f-49ce-91f3-34c1213746d8))
(fp_line (start 17 -2) (end -4.2 -2) (layer "F.SilkS") (width 0.12) (tstamp c1d01f2b-f45c-4cb9-b5bf-219aa60b0ea2))
(fp_line (start -4.2 14) (end 17 14) (layer "F.SilkS") (width 0.12) (tstamp c8348631-404d-4e66-a92f-6abdda5d5496))
(fp_line (start -4.2 -2) (end -4.2 14) (layer "F.SilkS") (width 0.12) (tstamp d169ccd3-ab8c-409f-8140-98ac4d80171c))
(fp_line (start 13 3.75) (end 8.1 6) (layer "F.SilkS") (width 0.12) (tstamp fb9c178b-f3d0-4b11-be23-163bfb0daeef))
(fp_rect (start -5.2 -3) (end 18 15) (layer "F.CrtYd") (width 0.05) (fill none) (tstamp 30abb9a4-6a70-4e36-840d-453db3cb840e))
(pad "1" thru_hole circle (at 0 0) (size 2.3 2.3) (drill 1.3) (layers *.Cu *.Mask) (tstamp da302846-016d-4be2-af55-6d603d02eb89))
(pad "2" thru_hole circle (at 0 12) (size 2.3 2.3) (drill 1.3) (layers *.Cu *.Mask) (tstamp c9b530ce-e490-420e-928e-df4bf9bc5adc))
(pad "3" thru_hole circle (at -2 6) (size 2.3 2.3) (drill 1.3) (layers *.Cu *.Mask) (tstamp c164a52d-67af-4765-976d-f02114341851))
(pad "4" thru_hole circle (at 12.2 12) (size 2.3 2.3) (drill 1.3) (layers *.Cu *.Mask) (tstamp c518c217-c92c-446b-ac12-3b43c18b8312))
)

View File

@ -0,0 +1,58 @@
(footprint "RotaryEncoder_Alps_EC12E-Switch_Vertical_H20mm" (version 20211014) (generator pcbnew)
(layer "F.Cu")
(tedit 6220DEE8)
(descr "Alps rotary encoder, EC12E... with switch, vertical shaft, http://www.alps.com/prod/info/E/HTML/Encoder/Incremental/EC12E/EC12E1240405.html & http://cdn-reichelt.de/documents/datenblatt/F100/402097STEC12E08.PDF")
(tags "rotary encoder")
(attr through_hole)
(fp_text reference "REF**" (at -4.7 -7.2) (layer "F.SilkS")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp 3230eb40-7bc6-4e5e-9d9e-ed2d003f678f)
)
(fp_text value "RotaryEncoder_Alps_EC12E-Switch_Vertical_H20mm" (at 0 7.9) (layer "F.Fab")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp d2467a1a-9475-484b-816d-d3278d65b6ae)
)
(fp_text user "${REFERENCE}" (at 4 4.1) (layer "F.Fab")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp fa348cbb-8f00-4f00-86b6-34a42c5da4b2)
)
(fp_line (start 6.7 3.7) (end 6.7 6.3) (layer "F.SilkS") (width 0.12) (tstamp 13bda85d-bdb4-4028-8655-ca62082bbd0e))
(fp_line (start -1.9 -6.3) (end -6.7 -6.3) (layer "F.SilkS") (width 0.12) (tstamp 28877f51-a477-4be7-81a8-44ee712ec7d3))
(fp_line (start -7.2 -4.1) (end -7.5 -3.8) (layer "F.SilkS") (width 0.12) (tstamp 2d38f326-70be-48c0-9620-f374e6b44553))
(fp_line (start 6.7 6.3) (end 1.8 6.3) (layer "F.SilkS") (width 0.12) (tstamp 38834dde-49a4-4749-b387-93717fe74f4e))
(fp_line (start 6.7 -6.3) (end 6.7 -3.7) (layer "F.SilkS") (width 0.12) (tstamp 39160ce7-41b6-4f4c-925c-316217a932c4))
(fp_line (start 0 -0.5) (end 0 0.5) (layer "F.SilkS") (width 0.12) (tstamp 6ccf62e1-00c5-4e79-a745-289343765f26))
(fp_line (start -6.7 -6.3) (end -6.7 -3.8) (layer "F.SilkS") (width 0.12) (tstamp 7a92dacf-b8e9-4fc9-b96c-8a353418d4e1))
(fp_line (start -7.8 -4.1) (end -7.2 -4.1) (layer "F.SilkS") (width 0.12) (tstamp 9ddf10e3-9a31-4929-b680-2824fd2c0b53))
(fp_line (start 1.8 -6.3) (end 6.7 -6.3) (layer "F.SilkS") (width 0.12) (tstamp ccbb416c-3309-48c4-93c5-907d5564b1e9))
(fp_line (start 6.7 -1.3) (end 6.7 1.3) (layer "F.SilkS") (width 0.12) (tstamp db916804-132c-4833-8e4e-e331d03795fe))
(fp_line (start -7.5 -3.8) (end -7.8 -4.1) (layer "F.SilkS") (width 0.12) (tstamp e4b61a90-9fdc-4218-9938-e16c6f7c1ca6))
(fp_line (start -1.8 6.3) (end -6.7 6.3) (layer "F.SilkS") (width 0.12) (tstamp eceb0525-a06c-4fa4-a0f2-8145028606d4))
(fp_line (start -6.7 6.3) (end -6.7 3.5) (layer "F.SilkS") (width 0.12) (tstamp f4ce0425-7c60-4743-a869-ee9f6d7040b0))
(fp_line (start -0.5 0) (end 0.5 0) (layer "F.SilkS") (width 0.12) (tstamp f733798e-9aaa-4c97-9f3c-157847976754))
(fp_circle (center 0 0) (end 3 0) (layer "F.SilkS") (width 0.12) (fill none) (tstamp df367f70-b410-4873-ad4b-63a9c86a05ca))
(fp_line (start -9 -7.35) (end -9 7.35) (layer "F.CrtYd") (width 0.05) (tstamp 4f32e0aa-f6fb-4cf3-831e-4b12621e63dc))
(fp_line (start 8.5 7.35) (end 8.5 -7.35) (layer "F.CrtYd") (width 0.05) (tstamp 732685a8-328e-432e-8c85-ee4b2fffe0b0))
(fp_line (start -9 -7.35) (end 8.5 -7.35) (layer "F.CrtYd") (width 0.05) (tstamp 82d0b3be-eea8-4bc5-8533-79dfb04cc7cb))
(fp_line (start 8.5 7.35) (end -9 7.35) (layer "F.CrtYd") (width 0.05) (tstamp 8e1082f7-21b2-416f-8e96-fe3bbc69296c))
(fp_line (start 6.6 -6.2) (end 6.6 6.2) (layer "F.Fab") (width 0.12) (tstamp 271d4529-d8e6-4856-bebe-d720a70a7c07))
(fp_line (start 6.6 6.2) (end -6.6 6.2) (layer "F.Fab") (width 0.12) (tstamp 36010ca5-cfa5-465a-8dc7-6635522cbf65))
(fp_line (start -5.6 -6.2) (end 6.6 -6.2) (layer "F.Fab") (width 0.12) (tstamp 5e1aadb2-931a-493b-9ac2-eb23274a2317))
(fp_line (start -3 0) (end 3 0) (layer "F.Fab") (width 0.12) (tstamp 6ab1e2c5-9404-47fc-9b40-3a7a764a6b49))
(fp_line (start -6.6 -5.1) (end -5.6 -6.2) (layer "F.Fab") (width 0.12) (tstamp bc10529c-c01c-4e90-a8ac-d5dae8a36dc8))
(fp_line (start 0 -3) (end 0 3) (layer "F.Fab") (width 0.12) (tstamp c9b8d358-c79a-4379-833f-0ced5eb8dee0))
(fp_line (start -6.6 6.2) (end -6.6 -5.1) (layer "F.Fab") (width 0.12) (tstamp fd4b24da-969c-4c00-b821-9c55ad3429fa))
(fp_circle (center 0 0) (end 3 0) (layer "F.Fab") (width 0.12) (fill none) (tstamp 8e42c692-a244-40c3-90a4-95d7f4220979))
(pad "A" thru_hole rect (at -7.5 -2.5) (size 2 2) (drill 1) (layers *.Cu *.Mask) (tstamp 959d1fc3-a140-4705-aad1-4aeaa394a1e6))
(pad "B" thru_hole circle (at -7.5 2.5) (size 2 2) (drill 1) (layers *.Cu *.Mask) (tstamp 84789112-335a-4624-b647-9a9c525f08b3))
(pad "C" thru_hole circle (at -7.5 0) (size 2 2) (drill 1) (layers *.Cu *.Mask) (tstamp 016d7760-6329-438b-8502-f5fbd25e0c16))
(pad "MP" thru_hole rect (at 0 5.6) (size 3 2.5) (drill oval 2.5 2) (layers *.Cu *.Mask) (tstamp 7caeec3f-9b1c-4bb8-930b-1529be94c357))
(pad "MP" thru_hole rect (at 0 -5.6) (size 3 2.5) (drill oval 2.5 2) (layers *.Cu *.Mask) (tstamp e030cdbc-437e-432d-9c29-74b330e45d14))
(pad "S1" thru_hole circle (at 7 -2.5) (size 2 2) (drill 1) (layers *.Cu *.Mask) (tstamp f38003a7-92db-4262-a7f0-21b2df95ac2a))
(pad "S2" thru_hole circle (at 7 2.5) (size 2 2) (drill 1) (layers *.Cu *.Mask) (tstamp 47686dc9-b9b5-4ae5-868a-c868ae958872))
(model "${KICAD6_3DMODEL_DIR}/Rotary_Encoder.3dshapes/RotaryEncoder_Alps_EC12E-Switch_Vertical_H20mm.wrl"
(offset (xyz -7.5 2.5 0))
(scale (xyz 1 1 1))
(rotate (xyz 0 0 0))
)
)

View File

@ -0,0 +1,65 @@
(footprint "blue_pill" (version 20211014) (generator pcbnew)
(layer "F.Cu")
(tedit 62261D40)
(attr through_hole)
(fp_text reference "REF**" (at 9.525 12.7) (layer "F.SilkS")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp f8c2bdc8-0f14-44b8-96a1-6b3ede9c5b64)
)
(fp_text value "blue_pill" (at 8.255 14.105) (layer "F.Fab")
(effects (font (size 1 1) (thickness 0.15)))
(tstamp 6fee9d9c-f0c8-4edf-980b-473836d5c178)
)
(fp_line (start -1.3 -2.5) (end -1.3 50.3) (layer "F.SilkS") (width 0.12) (tstamp 03b7ea59-04ff-4bfc-a26f-17e4b04b9d62))
(fp_line (start 9.75 -2.75) (end 5.5 -2.75) (layer "F.SilkS") (width 0.12) (tstamp 1df5d875-8a9c-43e5-b202-fc86872522cf))
(fp_line (start 16.5 -2.5) (end -1.3 -2.5) (layer "F.SilkS") (width 0.12) (tstamp 2a047ba3-1265-48c2-9aba-747f2aba922c))
(fp_line (start -1.3 50.3) (end 16.6 50.3) (layer "F.SilkS") (width 0.12) (tstamp 3597f731-eae6-47ca-8690-cde5f7bdb161))
(fp_line (start 9.75 0.75) (end 9.75 -2.75) (layer "F.SilkS") (width 0.12) (tstamp 6577e2d6-e771-4f1a-b78b-c897f7ae89cb))
(fp_line (start 5.5 -2.75) (end 5.5 0.75) (layer "F.SilkS") (width 0.12) (tstamp bf3dac99-ac50-4ac6-bfbd-9ed628e3720e))
(fp_line (start 16.6 50.3) (end 16.6 -2.5) (layer "F.SilkS") (width 0.12) (tstamp c719e44a-a7cf-4402-b739-a46a404f89a2))
(fp_line (start 5.5 0.75) (end 9.75 0.75) (layer "F.SilkS") (width 0.12) (tstamp ced23a17-cc8a-4c5d-95f6-018b51394a9f))
(fp_line (start 18.6 54) (end -3.3 54) (layer "F.CrtYd") (width 0.05) (tstamp 7889cf67-d749-4721-9a05-b8f106a0c34d))
(fp_line (start -3.3 -3) (end -3.3 54) (layer "F.CrtYd") (width 0.1) (tstamp b1bbb12a-19e6-4036-b1b0-c1d0661cdfd6))
(fp_line (start -3.3 -3) (end 18.6 -3) (layer "F.CrtYd") (width 0.05) (tstamp ebb85895-3703-4d7d-81db-0607e5c7c87e))
(fp_line (start 18.6 -3) (end 18.6 54) (layer "F.CrtYd") (width 0.05) (tstamp f85d8a88-cc20-4a57-91db-da57a46bd0e8))
(pad "3V3" thru_hole circle (at 15.24 5.08) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 9429d18d-18ba-4899-a864-514af21c1c9e))
(pad "3V3" thru_hole circle (at 0 48.26) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp ab93c249-614f-4756-8205-775844995b38))
(pad "5V" thru_hole circle (at 0 43.18) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 9d2d5d11-17ad-498b-b650-ef6577a9e2e4))
(pad "G" thru_hole circle (at 15.24 2.54) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 5769ca6c-3a60-4d6a-b8b1-c7432d89c83e))
(pad "G" thru_hole circle (at 0 45.72) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 99122ab4-05b4-425f-afa6-c53cd70cfd8a))
(pad "G" thru_hole circle (at 15.24 0) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp a53e144c-ae51-4f49-839a-b31e423f0b9d))
(pad "NRST" thru_hole circle (at 15.24 7.62) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 89adf5f0-766a-45e3-af45-a3faf584a058))
(pad "PA0" thru_hole circle (at 15.24 38.1) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp e7e7fbd7-4b54-4338-b1d2-29f53f7b660c))
(pad "PA1" thru_hole circle (at 15.24 35.56) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp c14f5110-1d19-4caa-9122-5ac098ce414a))
(pad "PA2" thru_hole circle (at 15.24 33.02) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 3991cdf7-8300-4efb-bb38-01580a5689c5))
(pad "PA3" thru_hole circle (at 15.24 30.48) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 78e39cfa-07bc-4f7a-b896-73828b677fe1))
(pad "PA4" thru_hole circle (at 15.24 27.94) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 56bca0f5-d3d4-461e-b2b6-fc223cd81593))
(pad "PA5" thru_hole circle (at 15.24 25.4) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp f5742966-ec76-4f1f-88df-f64b9d56d458))
(pad "PA6" thru_hole circle (at 15.24 22.86) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp d5e75f75-0d2d-44be-ae3e-080c6022f848))
(pad "PA7" thru_hole circle (at 15.24 20.32) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp feef1a5d-b0e4-47c5-bf36-03b69c53c26e))
(pad "PA8" thru_hole circle (at 0 10.16) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp d1d00f7c-ba70-407d-8a05-6b69162b6688))
(pad "PA9" thru_hole circle (at 0 12.7) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 7efb9b93-c827-4b3b-a5d9-b36f9ef25816))
(pad "PA10" thru_hole circle (at 0 15.24) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 71175409-5161-4e7f-870a-7220bae2c840))
(pad "PA11" thru_hole circle (at 0 17.78) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 83d3b4b0-830f-4b2c-a2ad-25662b5585f5))
(pad "PA12" thru_hole circle (at 0 20.32) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 2c9a54f8-1020-4c9b-88be-de55d79c9941))
(pad "PA15" thru_hole circle (at 0 22.86) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp e6ecce2c-676a-4740-82a3-1cf281e0b525))
(pad "PB0" thru_hole circle (at 15.24 17.78) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 6531a13d-ba14-42d0-a09c-ec44f2278da1))
(pad "PB1" thru_hole circle (at 15.24 15.24) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 5f8423d6-a368-46fb-a863-e202201145ce))
(pad "PB3" thru_hole circle (at 0 25.4) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 41fc3f0d-22fa-48a7-9930-c2029b9b969a))
(pad "PB4" thru_hole circle (at 0 27.94) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp ba716453-7f84-4787-b000-a2ee3220be04))
(pad "PB5" thru_hole circle (at 0 30.48) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp ddb6da8f-716c-4060-b5a4-c4f35c7c375f))
(pad "PB6" thru_hole circle (at 0 33.02) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 0de60cee-8896-437b-a77d-cd13d6795028))
(pad "PB7" thru_hole circle (at 0 35.56) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 4033c1c8-aeee-45cd-a4cf-4f861de46bdb))
(pad "PB8" thru_hole circle (at 0 38.1) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 3f2a3830-7912-4fc3-8059-eef54d216ee3))
(pad "PB9" thru_hole circle (at 0 40.64) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp f555b93a-c2fc-4e0d-b244-9eb4c2e6b819))
(pad "PB10" thru_hole circle (at 15.24 12.7) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 90b36a28-d7c6-48d8-9dcb-2871978e5364))
(pad "PB11" thru_hole circle (at 15.24 10.16) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp a1908b8e-0825-48b3-8135-e1cc6c5b0526))
(pad "PB12" thru_hole circle (at 0 0) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 8a540c29-89ce-44a9-acf2-abe44ea3381b))
(pad "PB13" thru_hole circle (at 0 2.54) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 3ab34b92-d783-4739-b3ee-5ec0badcacc5))
(pad "PB14" thru_hole circle (at 0 5.08) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 7bdc6b61-1f4e-405d-addb-1f53ec9c409c))
(pad "PB15" thru_hole circle (at 0 7.62) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 781733b4-d333-437b-af9a-88f7d844e98c))
(pad "PC13" thru_hole circle (at 15.24 45.72) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp f5325825-1d7c-45fb-b4e1-4316fcafd9d2))
(pad "PC14" thru_hole circle (at 15.24 43.18) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 02fd0541-1fc4-49c6-9718-ed72e55c2174))
(pad "PC15" thru_hole circle (at 15.24 40.64) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 9111aca0-9ec0-4dd6-a8d4-54f6887adc07))
(pad "VBAT" thru_hole circle (at 15.24 48.26) (size 1.524 1.524) (drill 0.9) (layers *.Cu *.Mask) (tstamp 02d8ba94-59de-429f-94fd-4bb380c66404))
)

View File

@ -0,0 +1,3 @@
(fp_lib_table
(lib (name "fan_monitor")(type "KiCad")(uri "${KIPRJMOD}/fan_monitor.pretty")(options "")(descr ""))
)

View File

@ -0,0 +1,3 @@
(sym_lib_table
(lib (name "fan_monitor")(type "KiCad")(uri "${KIPRJMOD}/fan_monitor.kicad_sym")(options "")(descr ""))
)

Binary file not shown.

15
docs/encoder_accel.py Normal file
View File

@ -0,0 +1,15 @@
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
sns.set_theme(style="whitegrid")
a = 0.85
b = 0.2
x = np.arange(-5, 6)
y = np.copysign(a*abs(x) * 10**(b*abs(x)) * 0.1, x)
sns.lineplot(x=x, y=y, palette="tab10", linewidth=2.5)
plt.show()

View File

@ -1,23 +1,52 @@
pub enum ConfigError { use core::fmt;
LoadError,
}
use crate::lcd_gui::LCDScreen;
//---Config struct----------------------------------------------------------------------------------
#[derive(Copy, Clone)]
pub enum FanOutput { pub enum FanOutput {
P1, P1,
P2, P2,
} }
pub enum FanState { impl FanOutput {
ON,
OFF, pub fn from_bits(bits: u16) -> FanOutput {
if bits == 0 { return Self::P1 }
return Self::P2;
}
pub fn to_bits(&self) -> u16 {
match self {
Self::P1 => 0,
Self::P2 => 1,
}
}
} }
#[derive(Copy, Clone)]
pub struct CalData {
pub offset: f32,
pub raw_value: Option<f32>,
}
impl CalData {
pub fn new(offset: f32) -> CalData {
CalData {
offset,
raw_value: None,
}
}
}
#[derive(Copy, Clone)]
pub struct SystemConfig { pub struct SystemConfig {
pub max_temp_diff: f32, pub max_temp_diff: f32,
pub min_temp_diff: f32, pub min_temp_diff: f32,
pub ext_offset: f32, pub ext_offset: CalData,
pub p1_offset: f32, pub p1_offset: CalData,
pub p2_offset: f32, pub p2_offset: CalData,
pub fan_output: FanOutput, pub fan_output: FanOutput,
} }
@ -27,18 +56,263 @@ impl SystemConfig {
SystemConfig { SystemConfig {
max_temp_diff: 8.0, max_temp_diff: 8.0,
min_temp_diff: 4.0, min_temp_diff: 4.0,
ext_offset: 0.0, ext_offset: CalData::new(0.0),
p1_offset: 0.0, p1_offset: CalData::new(0.0),
p2_offset: 0.0, p2_offset: CalData::new(0.0),
fan_output: FanOutput::P1, fan_output: FanOutput::P1,
} }
} }
}
pub fn load() -> Result<ConfigError, SystemConfig> { //---Menu struct------------------------------------------------------------------------------------
unimplemented!(); const MENU_ENTRY_NB: usize = 6;
pub enum MenuState {
Scroll,
Entry,
}
pub struct Menu {
entries: [Entry; MENU_ENTRY_NB],
state: MenuState,
should_refresh: bool,
entry_index: usize,
}
impl Menu {
pub fn new(config: &SystemConfig) -> Menu {
Menu {
entries: [
Entry::new("fan out", EntryValue::FanOut (FanOutput::P1), config),
Entry::new("max diff", EntryValue::MaxTempDiff (0.0), config),
Entry::new("min diff", EntryValue::MinTempDiff (0.0), config),
Entry::new("ex", EntryValue::ExtOffset (CalData::new(0.0)), config),
Entry::new("s1", EntryValue::P1Offset (CalData::new(0.0)), config),
Entry::new("s2", EntryValue::P2Offset (CalData::new(0.0)), config),
],
state: MenuState::Scroll,
should_refresh: true,
entry_index: 0,
}
} }
pub fn store() -> SystemConfig { pub fn button_update(&mut self, config: &mut SystemConfig) -> bool {
unimplemented!();
self.should_refresh = true;
// update state machine
match self.state {
MenuState::Scroll => {
if self.entry_index == 0 { return true }
// read desired value from config
self.state = MenuState::Entry;
self.entries[self.entry_index - 1].select(config);
},
MenuState::Entry => {
// write modified value to config
self.state = MenuState::Scroll;
self.entries[self.entry_index - 1].deselect(config);
}
}
false
}
pub fn movement_update(&mut self, movement: i32) {
if movement != 0 {
match self.state {
MenuState::Scroll => {
// convert movement to entry index
let mut index = self.entry_index as i32 + movement;
if index > MENU_ENTRY_NB as i32 {
index = MENU_ENTRY_NB as i32;
} else if index < 0 {
index = 0;
}
self.entry_index = index as usize;
},
MenuState::Entry => {
// update entry
self.entries[self.entry_index - 1].update(-movement);
//note : "-" sign is just to revert encoder direction, feels better when using
//the interface
},
}
self.should_refresh = true;
}
}
pub fn reset(&mut self) {
match self.state {
MenuState::Entry => {
// if an entry is selected, disguard all modifications
self.entries[self.entry_index - 1].disgard();
self.state = MenuState::Scroll;
},
_ => (),
}
self.entry_index = 0;
}
pub fn display<L: LCDScreen>(&mut self, screen: &mut L) {
if self.should_refresh {
// first line
screen.clear();
screen.set_cursor_pos(0);
let _ = write!(screen, "\u{007e}");
if self.entry_index == 0 {
let _ = write!(screen, "retour");
} else {
self.entries[self.entry_index - 1].display(screen);
}
// second line (if any)
if self.entry_index < MENU_ENTRY_NB {
screen.set_cursor_pos(0x40);
let _ = write!(screen, " ");
self.entries[self.entry_index].display(screen);
}
self.should_refresh = false;
}
}
}
pub enum EntryValue {
MaxTempDiff (f32),
MinTempDiff (f32),
ExtOffset (CalData),
P1Offset (CalData),
P2Offset (CalData),
FanOut (FanOutput),
}
impl EntryValue {
fn modify(&mut self, n: i32) {
use libm::{powf, copysignf, fabsf};
use crate::utils::TEMP_RANGE;
match self {
Self::MaxTempDiff (val) | Self::MinTempDiff (val) => {
*val += copysignf(fabsf(n as f32) * 0.85 * powf(10.0, 0.15 * fabsf(n as f32))
* 0.1, n as f32);
// avoid display issues by limiting value range
if *val > 99.9 { *val = 99.9; }
else if *val < -99.9 { *val = -99.9; }
},
Self::ExtOffset (data) | Self::P1Offset (data) | Self::P2Offset (data) => {
data.offset += copysignf(fabsf(n as f32) * 0.85
* powf(10.0, 0.15 * fabsf(n as f32)) * 0.1, n as f32);
// avoid limiting issues like before, taking probe bounds into account
if data.offset + TEMP_RANGE.end > 99.9 {
data.offset = 99.9 - TEMP_RANGE.end;
}
else if data.offset + TEMP_RANGE.start < -99.9 {
data.offset = -99.9 - TEMP_RANGE.start;
}
},
Self::FanOut (output) => {
if n%2 != 0 {
match output {
FanOutput::P1 => *output = FanOutput::P2,
FanOutput::P2 => *output = FanOutput::P1,
}}}}
}
fn load(&mut self, config: &SystemConfig) {
match self {
Self::MaxTempDiff (val) => *val = config.max_temp_diff,
Self::MinTempDiff (val) => *val = config.min_temp_diff,
Self::ExtOffset (data) => *data = config.ext_offset,
Self::P1Offset (data) => *data = config.p1_offset,
Self::P2Offset (data) => *data = config.p2_offset,
Self::FanOut (val) => *val = config.fan_output,
};
}
fn store(&mut self, config: &mut SystemConfig) {
match self {
Self::MaxTempDiff (val) => config.max_temp_diff = *val,
Self::MinTempDiff (val) => config.min_temp_diff = *val,
Self::ExtOffset (data) => config.ext_offset = *data,
Self::P1Offset (data) => config.p1_offset = *data,
Self::P2Offset (data) => config.p2_offset = *data,
Self::FanOut (val) => config.fan_output = *val,
};
}
}
impl fmt::Display for EntryValue {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
use crate::lcd_gui::Temp;
match self {
Self::MaxTempDiff (val) | Self::MinTempDiff (val) =>
formatter.write_fmt(format_args!("{:.1}", val)),
Self::ExtOffset (data) | Self::P1Offset (data) | Self::P2Offset (data) => {
let temp: Temp = data.raw_value.map(|val| val + data.offset).into();
formatter.write_fmt(format_args!("{:.1}({:.1})", data.offset, temp))
},
Self::FanOut (output) => {
match output {
FanOutput::P1 => formatter.write_fmt(format_args!("1")),
FanOutput::P2 => formatter.write_fmt(format_args!("2")),
}}}
}
}
pub struct Entry {
text: &'static str,
value: EntryValue,
is_selected: bool,
}
impl Entry {
pub fn new(text: &'static str, mut value: EntryValue, config: &SystemConfig) -> Entry {
value.load(config);
Entry {
text,
value,
is_selected: false,
}
}
pub fn display<B: core::fmt::Write>(&self, buffer: &mut B) {
let _ = match self.is_selected {
true => write!(buffer, "{}:{}", self.text, self.value),
false => write!(buffer, "{} {}", self.text, self.value),
};
}
pub fn select(&mut self, config: &SystemConfig) {
self.is_selected = true;
self.value.load(config);
}
pub fn deselect(&mut self, config: &mut SystemConfig) {
self.is_selected = false;
self.value.store(config);
}
pub fn disgard(&mut self) {
self.is_selected = false;
}
pub fn update(&mut self, n: i32) {
self.value.modify(n);
} }
} }

View File

@ -17,10 +17,16 @@ use hd44780_driver::{
}; };
use crate::{ use crate::{
config::SystemConfig,
state::SystemState, state::SystemState,
config::{Menu, SystemConfig, FanOutput},
}; };
//--------------------------------------------------------------------------------------------------
/* GUI config */
pub const GUI_TICK_SEC: f32 = 0.2;
const GUI_ERROR_SEC: f32 = 0.8;
//---Temp Enum-------------------------------------------------------------------------------------- //---Temp Enum--------------------------------------------------------------------------------------
/// A simple enum to handle displaying temps on the GUI. Temperatures can be valid or not. An /// A simple enum to handle displaying temps on the GUI. Temperatures can be valid or not. An
/// invalid temperature is displayed as "inval°C" whereas a valid temperature is displayed as /// invalid temperature is displayed as "inval°C" whereas a valid temperature is displayed as
@ -33,16 +39,54 @@ pub enum Temp {
impl fmt::Display for Temp { impl fmt::Display for Temp {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
Temp::Valid (deg) => formatter.write_fmt(format_args!("{:.2}", deg)), Temp::Valid (deg) => formatter.write_fmt(format_args!("{:.1}", deg)),
Temp::Invalid => formatter.write_str("inval"), Temp::Invalid => formatter.write_str("inval"),
} }
} }
} }
impl core::convert::From<Option<f32>> for Temp {
fn from(val: Option<f32>) -> Self {
match val {
Some(deg) => Temp::Valid(deg),
None => Temp::Invalid,
}
}
}
impl core::convert::From<f32> for Temp {
fn from(val: f32) -> Self {
Temp::Valid(val)
}
}
impl core::cmp::PartialEq<Temp> for Temp {
fn eq(&self, other: &Self) -> bool {
match self {
Self::Valid (val) => match other {
Self::Invalid => false,
Self::Valid (other_val) => val == other_val,
},
Self::Invalid => match other {
Self::Invalid => true,
_ => false,
},
}
}
}
//---LCDGui Struct---------------------------------------------------------------------------------- //---LCDGui Struct----------------------------------------------------------------------------------
pub enum GUIState {
Off,
Idle,
Menu,
Error (&'static str),
}
/// Manages the lcd screen and inputs (encoder + button) and display relevant information. Can also /// Manages the lcd screen and inputs (encoder + button) and display relevant information. Can also
/// be used to configure the system. The update() function should be called frequently to refresh /// be used to configure the system. The update() function should be called frequently to refresh
/// the GUI (every 0.2s is enough) /// the GUI (every 0.2s is enough).
pub struct LCDGui<L, Q, B> pub struct LCDGui<L, Q, B>
where where
L: LCDScreen, L: LCDScreen,
@ -53,9 +97,14 @@ where
qei: Q, qei: Q,
button: &'static AtomicBool, button: &'static AtomicBool,
backlight: Option<B>, backlight: Option<B>,
count: u16, count: i32,
state: GUIState,
menu: Menu,
ext_deg: Temp, ext_deg: Temp,
p1_deg: Temp, p1_deg: Temp,
p2_deg: Temp,
should_refresh: bool,
blink_counter: i32,
} }
impl<L, Q, B> LCDGui<L, Q, B> impl<L, Q, B> LCDGui<L, Q, B>
@ -65,19 +114,27 @@ where
B: OutputPin, B: OutputPin,
{ {
pub fn new(lcd: L, qei: Q, button: &'static AtomicBool, backlight: Option<B>) /// Create and configure a new GUI. By default the screen will display the idle screen.
pub fn new(lcd: L, qei: Q, button: &'static AtomicBool, backlight: Option<B>,
config: &SystemConfig)
-> LCDGui<L, Q, B> { -> LCDGui<L, Q, B> {
use hd44780_driver::{Cursor, CursorBlink, Display}; use hd44780_driver::{Cursor, CursorBlink, Display};
let count = qei.count(); let count = qei.count() as i32;
let mut gui = LCDGui { let mut gui = LCDGui {
lcd, lcd,
qei, qei,
button, button,
backlight, backlight,
count, count,
state: GUIState::Idle,
menu: Menu::new(config),
ext_deg: Temp::Invalid, ext_deg: Temp::Invalid,
p1_deg: Temp::Invalid, p1_deg: Temp::Invalid,
p2_deg: Temp::Invalid,
should_refresh: true,
blink_counter: 0,
}; };
if let Some(bl) = &mut gui.backlight { let _ = bl.set_high(); }; if let Some(bl) = &mut gui.backlight { let _ = bl.set_high(); };
@ -87,52 +144,157 @@ where
gui.lcd.set_display_mode( gui.lcd.set_display_mode(
DisplayMode { DisplayMode {
display: Display::On, display: Display::On,
cursor_visibility: Cursor::Visible, cursor_visibility: Cursor::Invisible,
cursor_blink: CursorBlink::On, cursor_blink: CursorBlink::Off,
} });
);
let _ = gui.lcd.write_str("Hello world!");
gui gui
} }
pub fn update<O: OutputPin>(&mut self, state: &mut SystemState<O>) { /// Perform the necessary operations after an action on the button or the encoder. This
/// function should be called frequently (every 0.2s is enough) to keep track of the state of
/// the encoder. For added reactivness, it can also be called on a button press. The function
/// can modifify the system's config through the system state and will take care of updating
/// the latter. Return true when something has been updated during the function call, usefull
/// for implementing powersaving features.
pub fn update<O: OutputPin>(&mut self, state: &mut SystemState<O>) -> bool {
self.ext_deg = match state.ext_temp() { let mut input_update = false;
Some(deg) => Temp::Valid(deg),
None => Temp::Invalid,
};
self.p1_deg = match state.p1_temp() { // manage button press
Some(deg) => Temp::Valid(deg),
None => Temp::Invalid,
};
//TODO deduplicate button detection
if self.button.swap(false, Ordering::AcqRel) { if self.button.swap(false, Ordering::AcqRel) {
self.lcd.write_str("paf").unwrap(); input_update = true;
// update state machine
match self.state {
GUIState::Off => {
self.state = GUIState::Idle;
self.lcd.clear();
if let Some(bl) = &mut self.backlight { let _ = bl.set_high(); };
self.should_refresh = true;
},
GUIState::Idle => {
self.state = GUIState::Menu;
self.menu.display(&mut self.lcd);
},
GUIState::Menu => {
//TODO improve that
let mut config: SystemConfig = *state.config();
if self.menu.button_update(&mut config) {
self.state = GUIState::Idle;
self.update_temps(state);
} else {
state.update_config(config);
self.menu.display(&mut self.lcd);
}
},
GUIState::Error (_) => {
self.state = GUIState::Idle;
self.lcd.clear();
self.should_refresh = true;
}}}
// manage encoder movement
let count = self.qei.count() as i32 / 2;
let diff1 = count - self.count;
let diff2 = 511 - i32::abs(diff1);
let diff = if i32::abs(diff1) < diff2 {
diff1
} else {
diff2 * -i32::signum(diff1)
};
if diff != 0 {
input_update = true;
self.count = count;
} }
if self.count != self.qei.count() { // display relevant screen
self.count = self.qei.count(); match self.state {
self.lcd.set_cursor_pos(0x40); GUIState::Off => {},
self.lcd.write_str(" ").unwrap(); GUIState::Idle => {
self.lcd.set_cursor_pos(0x40); if self.should_refresh {
write!(self.lcd, "{}", self.qei.count()/2).unwrap(); display_idle_screen(&mut self.lcd, &self.ext_deg, &self.p1_deg, &self.p2_deg,
} &state.config().fan_output);
self.should_refresh = false;
}
},
GUIState::Menu => {
if diff != 0 {
self.menu.movement_update(diff);
self.menu.display(&mut self.lcd);
}
},
GUIState::Error (err)=> {
self.blink_counter += 1;
self.lcd.set_cursor_pos(0); if self.blink_counter as f32 * GUI_TICK_SEC >= 2.0*GUI_ERROR_SEC {
self.lcd.write_str(" ").unwrap(); let _ = write!(self.lcd, "Erreur: ");
self.lcd.set_cursor_pos(0); self.lcd.set_cursor_pos(0x40);
let _ = write!(self.lcd, "{}\u{00df}C", self.ext_deg); let _ = write!(self.lcd, "{}", err);
self.blink_counter = 0;
} else if self.blink_counter as f32 * GUI_TICK_SEC >= GUI_ERROR_SEC {
self.lcd.clear();
}
}}
self.lcd.set_cursor_pos(0x40); input_update
self.lcd.write_str(" ").unwrap(); }
self.lcd.set_cursor_pos(0x40);
let _ = write!(self.lcd, "{}\u{00df}C", self.p1_deg); /// Update the temperatures to display on the idle screen. Should be called whenever the
/// temperatures are modified.
pub fn update_temps<O: OutputPin>(&mut self, state: &SystemState<O>) {
self.ext_deg = state.ext_temp().into();
self.p1_deg = state.p1_temp().into();
self.p2_deg = state.p2_temp().into();
self.should_refresh = true;
}
pub fn sleep(&mut self) {
self.state = GUIState::Off;
// reset menu in case the user was in-menu
self.menu.reset();
// manage lcd
self.lcd.clear();
//TODO set display off ?
if let Some(bl) = &mut self.backlight { let _ = bl.set_low(); };
}
pub fn display_error(&mut self, error: &'static str) {
self.state = GUIState::Error (error);
self.blink_counter = 0;
} }
} }
fn display_idle_screen<L: LCDScreen>(screen: &mut L, ext_deg: &Temp, p1_deg: &Temp, p2_deg: &Temp,
fan_output: &FanOutput) {
// display temperatures
screen.clear();
screen.set_cursor_pos(0);
let _ = write!(screen, "Ext:{}", ext_deg);
screen.set_cursor_pos(0x41);
let _ = write!(screen, "1:{}", p1_deg);
screen.set_cursor_pos(0x49);
let _ = write!(screen, "2:{}", p2_deg);
// display probe selection
match fan_output {
FanOutput::P1 => screen.set_cursor_pos(0x40),
FanOutput::P2 => screen.set_cursor_pos(0x48),
}
let _ = write!(screen, "*");
}
//---LCDScreen trait--------------------------------------------------------------------------------
/// A wrapper trait to complement the write trait by adding the extra functions provided by a lcd
/// screen, such as cursor position.
pub trait LCDScreen: core::fmt::Write { pub trait LCDScreen: core::fmt::Write {
fn reset(&mut self); fn reset(&mut self);

View File

@ -12,7 +12,6 @@ use cortex_m::interrupt::Mutex;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use embedded_hal::digital::{ use embedded_hal::digital::{
v2::OutputPin,
v1_compat::OldOutputPin, v1_compat::OldOutputPin,
}; };
@ -24,15 +23,16 @@ use stm32f1xx_hal::{
prelude::*, prelude::*,
timer::{Timer, CountDownTimer, Event}, timer::{Timer, CountDownTimer, Event},
qei::{QeiOptions, SlaveMode}, qei::{QeiOptions, SlaveMode},
rtc::Rtc, rtc::{Rtc, RtcClkLsi},
}; };
mod lcd_gui; mod lcd_gui;
use lcd_gui::LCDGui; use lcd_gui::{LCDGui, GUI_TICK_SEC};
mod utils; mod utils;
use utils::{ use utils::{
TemperatureProbe, TemperatureProbe,
ConfigStorage,
}; };
mod config; mod config;
@ -44,10 +44,10 @@ use state::SystemState;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/* system config */ /* system config */
const GUI_TICK_SEC: f32 = 0.2; const AWAKE_TIMEOUT_SEC: f32 = 20.0;
const HEARTBEAT_SEC: f32 = 1.0; const HEARTBEAT_SEC: f32 = 1.0;
const TEMPS_TICK_SEC: u32 = 2; const TEMPS_TICK_SEC: u32 = 30;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/* interrupt variables */ /* interrupt variables */
@ -59,15 +59,30 @@ static TICK_TIMER: Mutex<RefCell<Option<CountDownTimer<pac::TIM2>>>>
= Mutex::new(RefCell::new(None)); = Mutex::new(RefCell::new(None));
// button interrupt // button interrupt
static BUTTON_PIN: Mutex<RefCell<Option<gpiob::PB8<Input<PullUp>>>>> static BUTTON_PIN: Mutex<RefCell<Option<gpiob::PB8<Input<Floating>>>>>
= Mutex::new(RefCell::new(None)); = Mutex::new(RefCell::new(None));
static BUTTON_FLAG: AtomicBool = AtomicBool::new(false); static BUTTON_FLAG: AtomicBool = AtomicBool::new(false);
// temps interrupt // temps interrupt
static RTC: Mutex<RefCell<Option<Rtc>>> = Mutex::new(RefCell::new(None)); static RTC: Mutex<RefCell<Option<Rtc::<RtcClkLsi>>>> = Mutex::new(RefCell::new(None));
static G_EXTI: Mutex<RefCell<Option<EXTI>>> = Mutex::new(RefCell::new(None)); static G_EXTI: Mutex<RefCell<Option<EXTI>>> = Mutex::new(RefCell::new(None));
static TEMP_FLAG: AtomicBool = AtomicBool::new(false); static TEMP_FLAG: AtomicBool = AtomicBool::new(false);
//--------------------------------------------------------------------------------------------------
/* power management */
enum PowerState {
Awake,
Sleeping,
}
//--------------------------------------------------------------------------------------------------
/* error management */
enum ErrorState {
NoError,
NewError (&'static str),
HandlingError,
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/* interrupt service routines */ /* interrupt service routines */
#[interrupt] #[interrupt]
@ -126,16 +141,16 @@ fn main() -> ! {
let mut dp = pac::Peripherals::take().unwrap(); let mut dp = pac::Peripherals::take().unwrap();
// clocks config // clocks config
let mut rcc = dp.RCC.constrain(); let rcc = dp.RCC.constrain();
let mut flash = dp.FLASH.constrain(); let mut flash = dp.FLASH.constrain();
let clocks = rcc.cfgr let clocks = rcc.cfgr
.use_hse(8.mhz()) .use_hse(8.mhz())
.freeze(&mut flash.acr); .freeze(&mut flash.acr);
// GPIOs // GPIOs
let mut gpioa = dp.GPIOA.split(&mut rcc.apb2); let mut gpioa = dp.GPIOA.split();
let mut gpiob = dp.GPIOB.split(&mut rcc.apb2); let mut gpiob = dp.GPIOB.split();
let mut gpioc = dp.GPIOC.split(&mut rcc.apb2); let mut gpioc = dp.GPIOC.split();
// setup LED // setup LED
let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh); let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh);
@ -146,7 +161,7 @@ fn main() -> ! {
}); });
// Configure the timer 2 as tick timer // Configure the timer 2 as tick timer
let mut timer = Timer::tim2(dp.TIM2, &clocks, &mut rcc.apb1) let mut timer = Timer::tim2(dp.TIM2, &clocks)
.start_count_down(((1.0/GUI_TICK_SEC) as u32).hz()); .start_count_down(((1.0/GUI_TICK_SEC) as u32).hz());
timer.listen(Event::Update); timer.listen(Event::Update);
@ -159,8 +174,8 @@ fn main() -> ! {
dp.EXTI.imr.write(|w| w.mr17().set_bit()); dp.EXTI.imr.write(|w| w.mr17().set_bit());
// setup RTC // setup RTC
let mut backup_domain = rcc.bkp.constrain(dp.BKP, &mut rcc.apb1, &mut dp.PWR); let mut backup_domain = rcc.bkp.constrain(dp.BKP, &mut dp.PWR);
let mut rtc = Rtc::rtc(dp.RTC, &mut backup_domain); let mut rtc = Rtc::<RtcClkLsi>::rtc(dp.RTC, &mut backup_domain);
rtc.set_alarm(rtc.current_time() + TEMPS_TICK_SEC); rtc.set_alarm(rtc.current_time() + TEMPS_TICK_SEC);
rtc.listen_alarm(); rtc.listen_alarm();
@ -168,7 +183,21 @@ fn main() -> ! {
RTC.borrow(cs).borrow_mut().replace(rtc) RTC.borrow(cs).borrow_mut().replace(rtc)
}); });
let mut afio = dp.AFIO.constrain(&mut rcc.apb2); let mut afio = dp.AFIO.constrain();
// initialize system state
let mut config_storage = ConfigStorage::new(backup_domain, dp.CRC.new());
let mut error_state = ErrorState::NoError;
let config = match config_storage.load_config() {
Ok(conf) => conf,
Err(_) => {
error_state = ErrorState::NewError("config invalide");
let conf = SystemConfig::new();
config_storage.save_config(&conf);
conf
}};
let mut state = SystemState::new(config, config_storage,
gpiob.pb12.into_push_pull_output(&mut gpiob.crh));
// Setup display // Setup display
let mut gui = { let mut gui = {
@ -193,7 +222,7 @@ fn main() -> ! {
// Force write mode // Force write mode
let mut rw_pin = gpioa.pa9.into_push_pull_output(&mut gpioa.crh); let mut rw_pin = gpioa.pa9.into_push_pull_output(&mut gpioa.crh);
rw_pin.set_low().unwrap(); rw_pin.set_low();
let lcd = HD44780::new_8bit( let lcd = HD44780::new_8bit(
OldOutputPin::new(rs_pin), OldOutputPin::new(rs_pin),
@ -210,9 +239,9 @@ fn main() -> ! {
); );
// setup button (interrupt) // setup button (interrupt)
let mut but_pin = gpiob.pb8.into_pull_up_input(&mut gpiob.crh); let mut but_pin = gpiob.pb8.into_floating_input(&mut gpiob.crh);
but_pin.make_interrupt_source(&mut afio); but_pin.make_interrupt_source(&mut afio);
but_pin.trigger_on_edge(&dp.EXTI, Edge::RISING); but_pin.trigger_on_edge(&dp.EXTI, Edge::Rising);
but_pin.enable_interrupt(&dp.EXTI); but_pin.enable_interrupt(&dp.EXTI);
cortex_m::interrupt::free(|cs| { cortex_m::interrupt::free(|cs| {
@ -223,14 +252,14 @@ fn main() -> ! {
let backlight_pin = gpiob.pb9.into_push_pull_output(&mut gpiob.crh); let backlight_pin = gpiob.pb9.into_push_pull_output(&mut gpiob.crh);
// setup encoder // setup encoder
let enc = Timer::tim4(dp.TIM4, &clocks, &mut rcc.apb1) let enc = Timer::tim4(dp.TIM4, &clocks)
.qei((gpiob.pb6, gpiob.pb7), &mut afio.mapr, .qei((gpiob.pb6, gpiob.pb7), &mut afio.mapr,
QeiOptions { QeiOptions {
slave_mode:SlaveMode::EncoderMode2, slave_mode:SlaveMode::EncoderMode1,
auto_reload_value: 200 auto_reload_value: 1022,
}); });
LCDGui::new(lcd, enc, &BUTTON_FLAG, Some(backlight_pin)) LCDGui::new(lcd, enc, &BUTTON_FLAG, Some(backlight_pin), state.config())
}; };
let exti = dp.EXTI; let exti = dp.EXTI;
@ -254,42 +283,89 @@ fn main() -> ! {
// configure stop mode (not working yet, probably due to fake chip) // configure stop mode (not working yet, probably due to fake chip)
//dp.PWR.cr.write(|w| w.pdds().stop_mode()); //dp.PWR.cr.write(|w| w.pdds().stop_mode());
//dp.PWR.cr.write(|w| w.lpds().set_bit()); //dp.PWR.cr.write(|w| w.lpds().set_bit());
cp.SCB.set_sleepdeep();
// setup adc // setup adc
let mut adc = Adc::adc1(dp.ADC1, &mut rcc.apb2, clocks); let mut adc = Adc::adc1(dp.ADC1, clocks);
adc.set_sample_time(SampleTime::T_71); adc.set_sample_time(SampleTime::T_71);
let adc = RefCell::new(adc); let adc = RefCell::new(adc);
let ext1 = gpioa.pa4.into_analog(&mut gpioa.crl); let ext1 = gpioa.pa4.into_analog(&mut gpioa.crl);
let ext2 = gpioa.pa5.into_analog(&mut gpioa.crl); let ext2 = gpioa.pa5.into_analog(&mut gpioa.crl);
let p1_1 = gpioa.pa2.into_analog(&mut gpioa.crl); let p2_1 = gpioa.pa2.into_analog(&mut gpioa.crl);
let p1_2 = gpioa.pa3.into_analog(&mut gpioa.crl); let p2_2 = gpioa.pa3.into_analog(&mut gpioa.crl);
let p1_1 = gpioa.pa0.into_analog(&mut gpioa.crl);
let p1_2 = gpioa.pa1.into_analog(&mut gpioa.crl);
let mut ext_probe = TemperatureProbe::new(&adc, ext1, ext2).unwrap(); let mut ext_probe = TemperatureProbe::new(&adc, ext1, ext2).unwrap();
let mut p1_probe = TemperatureProbe::new(&adc, p1_1, p1_2).unwrap(); let mut p1_probe = TemperatureProbe::new(&adc, p1_1, p1_2).unwrap();
let mut p2_probe = TemperatureProbe::new(&adc, p2_1, p2_2).unwrap();
// initialize system state
let config = SystemConfig::new(); let mut power_state = PowerState::Awake;
let mut state = SystemState::new(config, gpiob.pb12.into_push_pull_output(&mut gpiob.crh)); let mut timeout = 0;
/* run */ /* run */
let _ = TEMP_FLAG.swap(true, Ordering::Release); let _ = TEMP_FLAG.swap(true, Ordering::Release);
// fix some weird bug caused by the debouncing capacitor of the button
for _ in 0..10 {
cortex_m::asm::wfi();
}
BUTTON_FLAG.store(false, Ordering::Release);
loop { loop {
//compute temps match error_state {
if TEMP_FLAG.swap(false, Ordering::AcqRel) { ErrorState::NoError => {
let ext_temp = ext_probe.read().ok(); if TEMP_FLAG.swap(false, Ordering::AcqRel) {
let p1_temp = p1_probe.read().ok();
state.update(ext_temp, p1_temp, None); // compute temps
} let ext_temp = ext_probe.read().ok();
let p1_temp = p1_probe.read().ok();
let p2_temp = p2_probe.read().ok();
gui.update(&mut state); state.update(ext_temp, p1_temp, p2_temp);
gui.update_temps(&mut state);
} else {
match gui.update(&mut state) {
true => timeout = 0,
false => timeout += 1,
}
// manage power state
match power_state {
PowerState::Awake => { // normal gui update
if timeout as f32 * GUI_TICK_SEC >= AWAKE_TIMEOUT_SEC {
// go to sleep
power_state = PowerState::Sleeping;
gui.sleep();
cp.SCB.set_sleepdeep();
}
},
PowerState::Sleeping => { // button was pressed during sleep
// wake up
power_state = PowerState::Awake;
cp.SCB.clear_sleepdeep();
}}}
},
ErrorState::NewError (err) => {
gui.display_error(err);
state.stop();
error_state = ErrorState::HandlingError;
},
ErrorState::HandlingError => {
if gui.update(&mut state) {
error_state = ErrorState::NoError;
state.reset();
ext_probe.reset().unwrap();
p1_probe.reset().unwrap();
p2_probe.reset().unwrap();
timeout = 0;
}
}}
// put device in sleep mode until next interrupt (button or timer) // put device in sleep mode until next interrupt (button or timer)
cortex_m::asm::wfi(); cortex_m::asm::wfi();
} }
} }

View File

@ -6,9 +6,11 @@ use crate::config::{
FanOutput, FanOutput,
}; };
use crate::utils::ConfigStorage;
pub enum FanState { pub enum FanState {
ON, On,
OFF, Off,
} }
pub struct Fan<O: OutputPin> { pub struct Fan<O: OutputPin> {
@ -23,19 +25,19 @@ impl<O: OutputPin> Fan<O> {
// erroring here means the pin is wrongly configured, there is nothing else to do... // erroring here means the pin is wrongly configured, there is nothing else to do...
pin.set_low().map_err(|_| "fan pin configuration").unwrap(); pin.set_low().map_err(|_| "fan pin configuration").unwrap();
Fan { Fan {
state: FanState::OFF, state: FanState::Off,
pin, pin,
} }
} }
pub fn on(&mut self) { pub fn on(&mut self) {
self.pin.set_high().map_err(|_| "fan pin configuration").unwrap(); self.pin.set_high().map_err(|_| "fan pin configuration").unwrap();
self.state = FanState::ON; self.state = FanState::On;
} }
pub fn off(&mut self) { pub fn off(&mut self) {
self.pin.set_low().map_err(|_| "fan pin configuration").unwrap(); self.pin.set_low().map_err(|_| "fan pin configuration").unwrap();
self.state = FanState::OFF; self.state = FanState::Off;
} }
pub fn state(&self) -> &FanState { &self.state } pub fn state(&self) -> &FanState { &self.state }
@ -43,6 +45,7 @@ impl<O: OutputPin> Fan<O> {
pub struct SystemState<O: OutputPin> { pub struct SystemState<O: OutputPin> {
config: SystemConfig, config: SystemConfig,
config_storage: ConfigStorage,
ext_temp: Option<f32>, ext_temp: Option<f32>,
p1_temp: Option<f32>, p1_temp: Option<f32>,
p2_temp: Option<f32>, p2_temp: Option<f32>,
@ -51,10 +54,12 @@ pub struct SystemState<O: OutputPin> {
impl<O: OutputPin> SystemState<O> { impl<O: OutputPin> SystemState<O> {
pub fn new(config: SystemConfig, fan_control_pin: O) -> SystemState<O> { pub fn new(config: SystemConfig, config_storage: ConfigStorage, fan_control_pin: O)
-> SystemState<O> {
SystemState { SystemState {
config, config,
config_storage,
ext_temp: None, ext_temp: None,
p1_temp: None, p1_temp: None,
p2_temp: None, p2_temp: None,
@ -70,12 +75,13 @@ impl<O: OutputPin> SystemState<O> {
pub fn update_config(&mut self, config: SystemConfig) { pub fn update_config(&mut self, config: SystemConfig) {
// remove offsets // remove offsets
let ext_temp = self.ext_temp.map(|temp| temp - self.config.ext_offset); let ext_temp = self.ext_temp.map(|temp| temp - self.config.ext_offset.offset);
let p1_temp = self.p1_temp.map(|temp| temp - self.config.p1_offset); let p1_temp = self.p1_temp.map(|temp| temp - self.config.p1_offset.offset);
let p2_temp = self.p2_temp.map(|temp| temp - self.config.p2_offset); let p2_temp = self.p2_temp.map(|temp| temp - self.config.p2_offset.offset);
// replace config // replace config
self.config = config; self.config = config;
self.config_storage.save_config(&self.config);
// reset fan state before recomputing fan state // reset fan state before recomputing fan state
self.fan.off(); self.fan.off();
@ -87,9 +93,14 @@ impl<O: OutputPin> SystemState<O> {
pub fn update(&mut self, ext_temp: Option<f32>, p1_temp: Option<f32>, p2_temp: Option<f32>) { pub fn update(&mut self, ext_temp: Option<f32>, p1_temp: Option<f32>, p2_temp: Option<f32>) {
// apply offsets // apply offsets
self.ext_temp = ext_temp.map(|temp| temp + self.config.ext_offset); self.ext_temp = ext_temp.map(|temp| temp + self.config.ext_offset.offset);
self.p1_temp = p1_temp.map(|temp| temp + self.config.p1_offset); self.p1_temp = p1_temp.map(|temp| temp + self.config.p1_offset.offset);
self.p2_temp = p2_temp.map(|temp| temp + self.config.p2_offset); self.p2_temp = p2_temp.map(|temp| temp + self.config.p2_offset.offset);
// update cal values
self.config.ext_offset.raw_value = ext_temp;
self.config.p1_offset.raw_value = p1_temp;
self.config.p2_offset.raw_value = p2_temp;
// select right probe and check if data is available // select right probe and check if data is available
let p = match match self.config.fan_output { let p = match match self.config.fan_output {
@ -112,16 +123,26 @@ impl<O: OutputPin> SystemState<O> {
// compute fan state // compute fan state
match self.fan.state() { match self.fan.state() {
FanState::ON => { FanState::On => {
if (p - ext) < self.config.min_temp_diff { if (p - ext) < self.config.min_temp_diff {
self.fan.off(); self.fan.off();
} }
}, },
FanState::OFF => { FanState::Off => {
if (p - ext) > self.config.max_temp_diff { if (p - ext) > self.config.max_temp_diff {
self.fan.on(); self.fan.on();
} }
}, }}
} }
pub fn stop(&mut self) {
self.fan.off();
}
pub fn reset(&mut self) {
self.ext_temp = None;
self.p1_temp = None;
self.p2_temp = None;
self.fan.off();
} }
} }

View File

@ -1,24 +1,39 @@
use core::{ use core::{
marker::PhantomData, marker::PhantomData,
cell::RefCell, cell::RefCell,
ops::Range,
}; };
use embedded_hal::adc::*; use embedded_hal::adc::*;
use stm32f1xx_hal::{
backup_domain::BackupDomain,
crc::Crc,
};
use libm::*; use libm::*;
use half::f16;
use crate::config::SystemConfig;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/* 2nd order linearisation factor for the temperature probe */ /* 2nd order linearisation factor for the temperature probe */
const A: f32 = -0.00058; const A: f32 = -0.000574;
const B: f32 = 0.0677; const B: f32 = 0.0676;
const C: f32 = -0.07; const C: f32 = -0.07;
//--------------------------------------------------------------------------------------------------
/* valid temperature range */
pub const TEMP_RANGE: Range<f32> = -10.0..45.0;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/* error management */ /* error management */
#[derive(Debug)] #[derive(Debug)]
pub enum ProbeError { pub enum ProbeError {
ReadError, ReadError,
Initializing, Initializing,
OutOfRange,
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -76,9 +91,9 @@ where
// compute first temp approximation to speed up stabilization // compute first temp approximation to speed up stabilization
let mut temp = 0.0; let mut temp = 0.0;
for _ in 0..10 { for _ in 0..10 {
temp += read_temp(&adc, &mut pos_pin, &mut neg_pin)?; temp += read_temp(adc, &mut pos_pin, &mut neg_pin)?;
} }
temp = temp/10.0; temp /= 10.0;
Ok(TemperatureProbe { Ok(TemperatureProbe {
adc, adc,
@ -97,7 +112,10 @@ where
match self.stabilized { match self.stabilized {
true => { true => {
self.filtered_temp += (temp - self.filtered_temp)/FILTER_TIME_CONSTANT; self.filtered_temp += (temp - self.filtered_temp)/FILTER_TIME_CONSTANT;
Ok(self.filtered_temp) match TEMP_RANGE.contains(&self.filtered_temp) {
true => Ok(self.filtered_temp),
false => Err(ProbeError::OutOfRange),
}
}, },
false => { // filter is not yet stabilized false => { // filter is not yet stabilized
let old_temp = self.filtered_temp; let old_temp = self.filtered_temp;
@ -112,5 +130,97 @@ where
}, },
} }
} }
pub fn reset(&mut self) -> Result<(), ProbeError>{
// re-compute first temp approximation to speed up stabilization
let mut temp = 0.0;
for _ in 0..10 {
temp += read_temp(self.adc, &mut self.pos_pin, &mut self.neg_pin)?;
}
temp /= 10.0;
self.filtered_temp = temp;
self.stabilized = false;
Ok(())
}
}
//--------------------------------------------------------------------------------------------------
/* ConfigStorage */
pub struct ConfigStorage {
backup_domain: BackupDomain,
crc: Crc,
}
impl ConfigStorage {
pub fn new(backup_domain: BackupDomain, crc: Crc) -> ConfigStorage {
ConfigStorage {
backup_domain,
crc,
}
}
pub fn load_config(&mut self) -> Result<SystemConfig, ()> {
use crate::config::{CalData, FanOutput};
// read from persistent memory
let mut values: [u16; 10] = [0; 10];
for (i, val) in values.iter_mut().enumerate() {
*val = self.backup_domain.read_data_register_low(i);
}
// compute CRC
self.crc.reset();
for i in (2..8).step_by(2) {
self.crc.write((values[i] as u32) << 16 | values[i+1] as u32);
}
let crc = (values[0] as u32) << 16 | values[1] as u32;
// parse config if CRC is valid
match crc != 0 && crc == self.crc.read() {
true => {
Ok(SystemConfig {
max_temp_diff: f16::from_bits(values[2]).to_f32(),
min_temp_diff: f16::from_bits(values[3]).to_f32(),
ext_offset: CalData::new(f16::from_bits(values[4]).to_f32()),
p1_offset: CalData::new(f16::from_bits(values[5]).to_f32()),
p2_offset: CalData::new(f16::from_bits(values[6]).to_f32()),
fan_output: FanOutput::from_bits(values[7]),
})
},
false => Err(()),
}
}
pub fn save_config(&mut self, config: &SystemConfig) {
// prepare buffer for later storage
let mut values: [u16; 10] = [0; 10];
values[2] = f16::from_f32(config.max_temp_diff).to_bits();
values[3] = f16::from_f32(config.min_temp_diff).to_bits();
values[4] = f16::from_f32(config.ext_offset.offset).to_bits();
values[5] = f16::from_f32(config.p1_offset.offset).to_bits();
values[6] = f16::from_f32(config.p2_offset.offset).to_bits();
values[7] = config.fan_output.to_bits();
// compute CRC
self.crc.reset();
for i in (2..8).step_by(2) {
self.crc.write((values[i] as u32) << 16 | values[i+1] as u32);
}
let crc = self.crc.read();
values[0] = ((crc >> 16) & 0xFFFF) as u16;
values[1] = (crc & 0xFFFF) as u16;
// write to persistent memory
for (i, val) in values.iter().enumerate() {
self.backup_domain.write_data_register_low(i, *val);
}
}
} }