From c1a390a6b96076dbb0d2a60b9a9c81bbe4538f60 Mon Sep 17 00:00:00 2001 From: Roman Belov Date: Sat, 13 Apr 2024 23:53:47 +0300 Subject: [PATCH] Improved GUI front-end and docs. --- README.md | 262 ++++++++++++++++++------------------ doc/CommandLineInterface.md | 93 ++++++++----- doc/GettingStarted.md | 30 +++-- doc/HardwareDesign.md | 10 +- doc/HardwareVESC.md | 8 +- doc/InputAnalogKnob.md | 3 + doc/InputPulseWidth.md | 5 +- doc/InputStepDirection.md | 36 ++++- doc/IntegritySelfTest.md | 31 ++++- doc/MachineProbe.md | 66 ++++----- doc/TroubleShooting.md | 16 +++ phobia/link.c | 37 +++-- phobia/phobia.c | 110 ++++++++++----- src/hal/hal.c | 65 ++++++--- src/hal/hal.h | 9 +- src/main.c | 46 +++---- src/phobia/pm.c | 9 +- src/phobia/pm.h | 4 +- src/phobia/pm_fsm.c | 15 +-- src/regdefs.h | 2 +- src/regfile.c | 4 +- src/shdefs.h | 6 +- 22 files changed, 536 insertions(+), 331 deletions(-) diff --git a/README.md b/README.md index 772943c..69e10c1 100644 --- a/README.md +++ b/README.md @@ -7,154 +7,154 @@ PMC is an open project that aims to build the quality permanent magnet synchronous machine (PMSM) controller for use in a variety of scopes like RC or electric transport. +## Brief + +PMC is ready to use in most intended applications. You can flash any supported +third-party hardware to work with PMC or use our original hardware. + +Read further in [doc/GettingStarted](doc/GettingStarted.md). + +There are a few videos about PMC on [youtube](https://www.youtube.com/@romblv). + ## Software features -* Sensorless vector control of PMSM by measurement of currents and voltages. -* Robust ORTEGA observer with gain scheduling against speed. -* Accurate KALMAN observer having convergence at HF injection. -* Flux weakening and MTPA control (**EXPERIMENTAL**). -* Three and two phase machine support. -* Hardware abstraction layer (HAL) over STM32F4 and STM32F7. -* Various controller hardware are supported (including VESC clones). -* Regular Command Line Interface (CLI) with autocompletion and history. -* Graphical front-end software based on +- Sensorless vector control of PMSM by measurement of currents and voltages. +- Robust ORTEGA observer with gain scheduling against speed. +- Accurate KALMAN observer having convergence at HF injection. +- Flux weakening and MTPA control (**EXPERIMENTAL**). +- Three and two phase machine support. +- Hardware abstraction layer (HAL) over STM32F4 and STM32F7. +- Various controller hardware are supported (including VESC clones). +- Regular Command Line Interface (CLI) with autocompletion and history. +- Graphical front-end software based on [Nuklear](https://github.com/Immediate-Mode-UI/Nuklear) and [SDL2](https://www.libsdl.org/). -* Non time-critical tasks are managed by +- Non time-critical tasks are managed by [FreeRTOS](http://www.freertos.org/). -* USB protocol stack from +- USB protocol stack from [CherryUSB](https://github.com/sakumisu/CherryUSB). -* Least Squares estimate library +- Least Squares estimate library [LSE](https://github.com/rombrew/lse). -* Phase current sampling schemes includes two or three sensors configuration +- Phase current sampling schemes includes two or three sensors configuration with inline or low-side placement. -* Self-adjustment of all onboard measurements (current and voltage) along +- Self-adjustment of all onboard measurements (current and voltage) along symmetrical channels. -* Advanced SVPWM scheme provides: - * Reduced switching losses and fully utilised DC link voltage. - * Reduced voltage distortion for precise control. - * Voltage hopping to get accurate ADC measurements with inline current sensors. - * Prevent bootstrap circuit undervoltage condition. - -* Terminal voltage measurements (TVM): - * Compensation of the voltage distortion caused by Dead-Time insertion. - * Back EMF voltage tracking to catch an already running machine. - * Self-test of the power stages integrity and machine wiring. - * Self-test of bootstrap retention time. - -* Automated machine parameters identification (with no external tools): - * Stator DC resistance (Rs). - * Stator AC impedance in DQ frame (L1, L2, R). - * Rotor flux linkage constant (lambda). - * Mechanical moment of inertia (Ja). - -* Automated configuration of external measurements: - * Discrete Hall sensors installation angles recognition. - * EABI resolution and direction adjustment. - -* Operation at low or zero speed: - * Forced control that applies a current vector without feedback to +- Advanced SVPWM scheme provides: + - Reduced switching losses and fully utilised DC link voltage. + - Reduced voltage distortion for precise control. + - Voltage hopping to get accurate ADC measurements with inline current sensors. + - Prevent bootstrap circuit undervoltage condition. + +- Terminal voltage measurements (TVM): + - Compensation of the voltage distortion caused by dead-time insertion. + - Back EMF voltage tracking to catch an already running machine. + - Self-test of the power stages integrity and machine wiring. + - Self-test of bootstrap retention time. + +- Automated machine parameters identification (with no external tools): + - Stator DC resistance (Rs). + - Stator AC impedance in DQ frame (L1, L2, R). + - Rotor flux linkage constant (lambda). + - Mechanical moment of inertia (Ja). + +- Automated configuration of external measurements: + - Discrete Hall sensors installation angles recognition. + - EABI resolution and direction adjustment. + +- Operation at low or zero speed: + - Forced control that applies a current vector without feedback to force rotor hold or spinup. - * Freewheeling. - * High Frequency Injection (HFI) based on magnetic saliency. - * Discrete Hall sensors. - * AB quadrature incremental encoder (EABI). - * Absolute encoder on SPI interface (AS5047). - * Analog Hall sensors and resolver decoder (**TODO**). - -* Nested control loops: - * Detached voltage monitoring. - * Current control PI regulator with feedforward compensation. - * Speed control PID regulator with load torque compensation. - * Location control with constant acceleration regulator. - -* Adjustable constraints: - * Phase current (forward and reverse, on HFI current, weakening D current, - with derate on PCB overheat or machine overheat). - * Machine voltage applied from VSI. - * DC link current consumption and regeneration. - * DC link overvoltage and undervoltage. - * Maximal speed and acceleration. - * Absolute location limits. - -* Input control interfaces: - * Analog input knob with brake signal. - * RC servo pulse width modulation. - * CAN bus flexible configurable data transfers. - * STEP/DIR (or CW/CCW) interface (**EXPERIMENTAL**). - * Manual control through CLI or graphical front-end. - * Custom embedded application can implement any control strategy. - -* Advanced CAN networking: - * Up to 30 nodes in peer network. - * Network survey on request (no heartbeat messages). - * Automated node address assignment. - * IO forwarding to log in to the remote node CLI. - * Flexible configurable data transfers. - -* Available information: - * Machine state (electrical position, speed, load torque). - * DC link voltage and current consumption. - * Information from temperature sensors. - * Total distance traveled. - * Battery energy (Wh) and charge (Ah) consumed. - * Fuel gauge percentage. + - Freewheeling. + - High Frequency Injection (HFI) based on magnetic saliency. + - Discrete Hall sensors. + - AB quadrature incremental encoder (EABI). + - Absolute encoder on SPI interface (AS5047). + - Analog Hall sensors and resolver decoder (**TODO**). + +- Nested control loops: + - Detached voltage monitoring. + - Current control PI regulator with feedforward compensation. + - Speed control PID regulator with load torque compensation. + - Location control with constant acceleration regulator. + +- Adjustable constraints: + - Phase current (forward and reverse, on HFI current, weakening D current). + - Hardware overtemperature protection (decrease phase current or halt). + - Machine voltage applied from VSI. + - DC link current consumption and regeneration. + - DC link overvoltage and undervoltage. + - Maximal speed (forward and reverse) and acceleration. + - Absolute location maximal and minimal limit. + +- Input control interfaces: + - Analog input knob with brake signal. + - RC servo pulse width modulation. + - CAN bus flexible configurable data transfers. + - STEP/DIR (or CW/CCW) interface (**EXPERIMENTAL**). + - Manual control through CLI or graphical front-end. + - Custom embedded application can implement any control strategy. + +- Advanced CAN networking: + - Up to 30 nodes in peer network. + - Network survey on request (no heartbeat messages). + - Automated node address assignment. + - IO forwarding to log in to the remote node CLI. + - Flexible configurable data transfers. + +- Available information: + - Machine state (electrical position, speed, load torque, etc.) + - DC link voltage and current consumption. + - Information from temperature sensors. + - Total distance traveled. + - Battery energy (Wh) and charge (Ah) consumed. + - Fuel gauge percentage. ## Hardware specification (`REV5A`) -* Dimension: 82mm x 55mm x 35mm. -* Weight: 40g (PCB) or about 400g (with wires and heatsink). -* Wires: 10 AWG. -* Connector: XT90-S and bullet 5.5mm. -* Battery voltage from 5v to 50v. -* Phase current up to 120A (with IPT007N06N, 60v, 0.75 mOhm). -* Light capacitor bank (4 x 4.7uF + 2 x 330uF). -* PWM frequency from 20 to 60 kHz. -* STM32F405RG microcontroller (Cortex-M4F at 168 MHz). - -* Onboard sensors: - * Two current shunts (0.5 mOhm) with amplifiers (AD8418) give a +- Dimension: 82mm x 55mm x 35mm. +- Weight: 40g (PCB) or about 400g (with wires and heatsink). +- Wires: 10 AWG. +- Connector: XT90-S and bullet 5.5mm. +- Battery voltage from 5v to 50v. +- Phase current up to 120A (with IPT007N06N, 60v, 0.75 mOhm). +- Light capacitor bank (4 x 4.7uF + 2 x 330uF). +- PWM frequency from 20 to 60 kHz. +- STM32F405RG microcontroller (Cortex-M4F at 168 MHz). + +- Onboard sensors: + - Two current shunts (0.5 mOhm) with amplifiers (AD8418) give a measuring range of 165A. - * Battery voltage from 0 to 60v. - * Three terminal voltages from 0 to 60v. - * Temperature of PCB with NTC resistor. - -* Machine interfaces: - * Discrete Hall sensors or EABI encoder (5v pull-up). - * External NTC resistor (e.g. machine temperature sensing). - -* Control interfaces: - * CAN transceiver with optional termination resistor on PCB (5v). - * USART to bootload and configure (3.3v). - * RC servo PWM or STEP/DIR (5v pull-up). - * Two analog input channels (from 0 to 6v). - -* Auxiliary interfaces: - * SPI port with alternative functions: ADC, DAC, GPIO (3.3v). - * BOOT pin combined with SWDIO to use embedded bootloader. - * External FAN control (5v, ~0.5A). - -* Power conversion: - * Battery voltage to 5v buck (~1A). - * 5v to 12v boost (~100 mA). - * 5v to 3.3v linear (~400 mA). - -## Status - -Now we can declare that PMC is ready to use in most intended applications. But -it may be difficult to configure the PMC for some types of machines. - -There are a few videos about PMC on [youtube](https://www.youtube.com/@romblv). - -Read further in [doc/GettingStarted](doc/GettingStarted.md). + - Battery voltage from 0 to 60v. + - Three terminal voltages from 0 to 60v. + - Temperature of PCB with NTC resistor. + +- Machine interfaces: + - Discrete Hall sensors or EABI encoder (5v pull-up). + - External NTC resistor (e.g. machine temperature sensing). + +- Control interfaces: + - CAN transceiver with optional termination resistor on PCB (5v). + - USART to bootload and configure (3.3v). + - RC servo PWM or STEP/DIR (5v pull-up). + - Two analog input channels (from 0 to 6v). + +- Auxiliary interfaces: + - SPI port with alternative functions: ADC, DAC, GPIO (3.3v). + - BOOT pin combined with SWDIO to use embedded bootloader. + - External FAN control (5v, ~0.5A). + +- Power conversion: + - Battery voltage to 5v buck (~1A). + - 5v to 12v boost (~100 mA). + - 5v to 3.3v linear (~400 mA). ## TODO -* Make a detailed documentation. -* Improve GUI front-end software. -* Add pulse output signal. -* Make a drawing of the heatsink case for `REV5A`. -* Design the new hardware for 120v battery voltage. +- Make a detailed documentation. +- Improve GUI front-end software. +- Add pulse output signal. +- Make a drawing of the heatsink case for `REV5A`. +- Design the new hardware for 120v battery voltage. diff --git a/doc/CommandLineInterface.md b/doc/CommandLineInterface.md index a64db46..d020405 100644 --- a/doc/CommandLineInterface.md +++ b/doc/CommandLineInterface.md @@ -7,28 +7,28 @@ CLI with autocompletion function and command history. These are the basic special keys that are used in the CLI: -* `Return` - Run the current line. -* `Backspace` or `Delete` - Erase last typed character. -* `Tab` or (@) - Automplete function. -* `Shift` + `Tab` - Automplete function reverse. -* `Ctrl` + `C` or `Ctrl` + `D` - Drop the content of the line or abort the command. -* `Ctrl` + `P` or `Up` or `*` - History function scroll up. -* `Ctrl` + `N` or `Down` or `!` - History function scroll down. +- `Return` - Run the current line. +- `Backspace` or `Delete` - Erase last typed character. +- `Tab` or (@) - Automplete function. +- `Shift` + `Tab` - Automplete function reverse. +- `Ctrl` + `C` or `Ctrl` + `D` - Drop the content of the line or abort the command. +- `Ctrl` + `P` or `Up` or `*` - History function scroll up. +- `Ctrl` + `N` or `Down` or `!` - History function scroll down. ## Register file concept -Register is a scalar variable known by its name and having associated +A register is a scalar variable known by its name and having associated attributes. All registers together are called the register file. This is a -convenient way to access all parameters using a single mechanism. There is a -`reg` command to work with registers from the CLI. There are several ways to -call this command: +convenient way to access all parameters in one way. There is a `reg` command to +work with registers from the CLI. There are several ways to call this +command. -* Without arguments it will list all registers and their values. -* You can specify a pattern by which registers will be filtered. A pattern can +- Without arguments it will list all registers and their current values. +- You can specify a pattern by which registers will be filtered. A pattern can be any part of the register name. -* If only one register matches the specified pattern the second parameter +- If only one register matches the specified pattern the second parameter specifies its new value. -* You can specify a register number instead of its name to refer the exactly +- You can specify a register number instead of its name to refer the exactly one register. Something like that: @@ -36,8 +36,8 @@ Something like that: (pmc) reg (pmc) reg -Almost all of the configuration process is to change the value of the -registers. +Almost all of the configuration process is to review and change the value of +the registers. You can also export all of configuration registers in plain text using a `config_reg` command. The output of this command can be fed back into the CLI @@ -51,25 +51,30 @@ at startup. (pmc) flash_prog -Note the different types of registers. There are registers intended for saving -as configuration. Other registers provide information to read only. Virtual -registers provide a different way to access other registers (usually this is -taking a value in different unit of measurement). There are also link registers -that are required to configure data transfer between different subsystems. +If you need to cleanup the flash storage do not forget to reboot PMC after. -Keep in mind each register can have its own write and read handler that can do -a complex non-obvious actions during access to it. + (pmc) flash_wipe + (pmc) ap_reboot + +Note the different types of registers. There are registers intended to storage +of configuration. Other registers provide some read-only information. Virtual +registers provide a different way to access already known registers (usually +this is taking a value in different unit of measurement). There are also link +registers that are required to configure data transfer between different +subsystems. + +Keep in mind each register can have its own write and read event handler that +can do any complex non-obvious actions during access to it. ## Linkage concept As we have already mentioned there are link registers. If we start accessing such a register we will be redirected to the link. For example the analog input module writes the control signal to register `ap.knob_reg_ID` but the value -falls into `pm.i_setpoint_current_pc`. You can configure `ap.knob_reg_ID` -to link it to another register if you want control another parameter. We -provide many registers in different units of measurement. You are free to -choose what to control current in Amperes or percentage from full scale or -something else. +falls into `pm.i_setpoint_current_pc`. You can configure `ap.knob_reg_ID` to +link it to another register if you want control another parameter. We provide +many registers in different units of measurement. You are free to choose how to +control current in Amperes or percentage from full scale or something else. There are telemetry module with 10 link registers. Choose any registers you need to be captured. @@ -78,12 +83,16 @@ need to be captured. (pmc) reg tlm.reg_ID1 pm.tvm_B (pmc) reg tlm.reg_ID2 ... -Telemetry grab into RAM and flush textual dump. +Command to grab telemetry into RAM and flush textual dump. (pmc) tlm_grab (pmc) tlm_flush_sync -Or live telemetry printout. +Run an endless loop grabbing until PMC stops with error. + + (pmc) tlm_watch + +Use a real-time telemetry printout. (pmc) tlm_live_sync @@ -91,6 +100,19 @@ Using CAN data pipes you are able to link register across CAN network. You can easily control many machines from single input. Build a traction control by exchange the speed signals across PMC instances. +## Textual transcription + +Some of integer registers printed out accompanied by textual transcription that +describes register current value. Typically this is a configuration register +responsible for selecting one of several possible options. Note that you must +assign a new value to the register to find out its transcription. + + (pmc) reg pm.config_IFB + 1 [151] pm.config_IFB = 2 (PM_IFB_ABC_INLINE) + +The textual transcription corresponds to the enumeration constants in the +source code of PMC. + ## Examples Show all raw feedback values that PMC uses in control loops. @@ -105,7 +127,7 @@ Enable control from analog input. (pmc) reg ap.knob_ENABLED 1 -Look for speed setpoint registers. +Show all speed setpoint registers. (pmc) reg pm.s_setpoint @@ -115,11 +137,10 @@ Assign the value of 700 to the register with ID 377. ## Basic commands -There are some commands that you can use to get started. Basic informational -commands. +Basic informational commands. - (pmc) ap_task_info - (pmc) ap_heap_info + (pmc) ap_dbg_task + (pmc) ap_dbg_heap Get firmware version info. diff --git a/doc/GettingStarted.md b/doc/GettingStarted.md index 5c3d7e2..1515d9a 100644 --- a/doc/GettingStarted.md +++ b/doc/GettingStarted.md @@ -1,7 +1,7 @@ ## Overview -This manual gives a basic info about Phobia Motor Controller (PMC). Look into -other documents for specific questions. +This manual gives a basic info about Phobia Motor Controller (PMC). See other +documents for specific topics. ## Hardware @@ -48,6 +48,8 @@ erased MCU) then short BOOT pin to +3.3v before the power up. +--/ --+ ``` +You also can use an USB connection if your hardware has one. + ## Software There are a few parts of software: @@ -117,18 +119,18 @@ embedded bootloader without BOOT pin. Just run the command in the CLI. Read the following documentation for setting PMC up. -* [Command Line Interface](CommandLineInterface.md) -* [Hardware Design](HardwareDesign.md) -* [Hardware VESC](HardwareVESC.md) -* [Integrity Self Test](IntegritySelfTest.md) -* [Machine Probe](MachineProbe.md) -* [Machine Tuning](MachineTuning.md) -* [High Frequency Injection](HighFrequencyInjection.md) -* [Input Analog Knob](InputAnalogKnob.md) -* [Input Pulse Width](InputPulseWidth.md) -* [Input STEP/DIR Interface](InputStepDirection.md) -* [Network CAN](NetworkCAN.md) -* [Trouble Shooting](TroubleShooting.md) +- [Command Line Interface](CommandLineInterface.md) +- [Hardware Design](HardwareDesign.md) +- [Hardware VESC](HardwareVESC.md) +- [Integrity Self Test](IntegritySelfTest.md) +- [Machine Probe](MachineProbe.md) +- [Machine Tuning](MachineTuning.md) +- [High Frequency Injection](HighFrequencyInjection.md) +- [Input Analog Knob](InputAnalogKnob.md) +- [Input Pulse Width](InputPulseWidth.md) +- [Input STEP/DIR Interface](InputStepDirection.md) +- [Network CAN](NetworkCAN.md) +- [Trouble Shooting](TroubleShooting.md) ## Feedback and support diff --git a/doc/HardwareDesign.md b/doc/HardwareDesign.md index bf8d538..e00eb80 100644 --- a/doc/HardwareDesign.md +++ b/doc/HardwareDesign.md @@ -50,12 +50,12 @@ PWM scheme as shown in the diagram. ``` Each half-bridge consists of two MOSFETs controlled by a gate drivers with a -specified Dead-Time `DET`. Depending on the direction of the current flow -during the Dead-Time the actual voltage on half-bridge may be different. The -amount of uncertainty in the output voltage `dU` expressed as follows: +specified dead-time `ZT`. Depending on the direction of the current flow during +the dead-time the actual voltage on half-bridge may be different. The amount of +uncertainty in the output voltage `dU` expressed as follows: ``` - 2 * DET * DC_link_voltage + 2 * ZT * DC_link_voltage dU = --------------------------- dT @@ -69,7 +69,7 @@ amount of uncertainty in the output voltage `dU` expressed as follows: || | --- | | |--+ | | | | | | | - +------+ --->| <--- DET | + +------+ --->| <--- ZT | | | | +---< Terminal | | | | | diff --git a/doc/HardwareVESC.md b/doc/HardwareVESC.md index 928f7ad..cfaf4bc 100644 --- a/doc/HardwareVESC.md +++ b/doc/HardwareVESC.md @@ -36,8 +36,14 @@ to upgrade the firmware you can use USB DFU or serial bootloader. Also check [GettingStarted](GettingStarted.md) page howto build and load the firmware to MCU. -## Interfaces +## Analog interfaces Note that VESC does not have voltage dividers on ADC pins. You should use external dividers or specify 3.3v levels on analog knob range configuration. +## Terminal voltages + +Note that VESC does not have required RC filters on the terminal voltage +measurement circuits. So you are not able to use dead-time distortion +compensation. + diff --git a/doc/InputAnalogKnob.md b/doc/InputAnalogKnob.md index a7f4243..4258524 100644 --- a/doc/InputAnalogKnob.md +++ b/doc/InputAnalogKnob.md @@ -21,6 +21,9 @@ to 5v) is fed to `BRK` pin. Unconnected inputs are pulled to `GND` inside PMC. | GND BRK ANG +5v | ``` +**WARNING**: Refer to your hardware manual or look into `src/hal/hw/...` +directory to find out actual pin mapping on your port. + ## Configuration First you need to figure out how the controller receives analog signals. Use diff --git a/doc/InputPulseWidth.md b/doc/InputPulseWidth.md index 1ffa7c1..352301a 100644 --- a/doc/InputPulseWidth.md +++ b/doc/InputPulseWidth.md @@ -15,6 +15,9 @@ The pulse signal is fed to PPM pin that must be 5v-tolerant. | +5v PPM GND | ``` +**WARNING**: Refer to your hardware manual or look into `src/hal/hw/...` +directory to find out actual pin mapping on your port. + ## Configuration First you need to enable the appropriate mode of the PPM interface. @@ -22,7 +25,7 @@ First you need to enable the appropriate mode of the PPM interface. (pmc) reg hal.PPM_mode 1 Now you can see how the controller receives the control signal. If variable -`ap.ppm_freq` is nonzero then pulse is caught. Use these registers to view +`ap.ppm_FREQ` is nonzero then pulse is caught. Use these registers to view pulse parameters. (pmc) reg ap.ppm_PULSE diff --git a/doc/InputStepDirection.md b/doc/InputStepDirection.md index 5cf3bdc..56cead5 100644 --- a/doc/InputStepDirection.md +++ b/doc/InputStepDirection.md @@ -15,6 +15,9 @@ The step and direction signals are fed to STEP and DIR pins. | STEP DIR GND | ``` +**WARNING**: Refer to your hardware manual or look into `src/hal/hw/...` +directory to find out actual pin mapping on your port. + ## Configuration First you need to enable the appropriate mode of the STEP interface. @@ -26,5 +29,36 @@ Now you can see how the controller receives the control signal. If variable (pmc) reg ap.step_POS -TODO +Choose what parameter you want to control. You can choose any of the registers +available for writing. By default the `pm.x_setpoint_location` register is +selected that mapped on absolute location in electrical radians. + + (pmc) reg ap.step_reg_ID + +Define the step length constant to convert steps from `ap.step_POS` register to +a setpoint value in `ap.step_reg_DATA` register. + + (pmc) reg ap.step_const_S + +Your probably should select location control loop. Note that machine must +already be configured to operate in speed control loop. + + (pmc) reg pm.config_LU_DRIVE 2 + +Now enable the machine startup control. The condition to start is no error code +in `pm.fsm_errno` register. + + (pmc) reg ap.step_STARTUP 1 + +## Precision + +You can change the timebase frequency of the timer that is used to sample STEP +and DIR signals. By increasing the frequency you decrease the minimum pulse +width that can be accurately detected. But we use DMA based software event +counting so a high frequency will cause a high computational load. + + (pmc) reg hal.STEP_frequency + +Maximal reasonable frequency is 1000000 Hz that gives a resolution about 1 us. +Thus the frequency of the STEP signal should not exceed 500 kHz. diff --git a/doc/IntegritySelfTest.md b/doc/IntegritySelfTest.md index bf73e56..7351370 100644 --- a/doc/IntegritySelfTest.md +++ b/doc/IntegritySelfTest.md @@ -2,6 +2,9 @@ This page describes how to verify the electrical integrity of PMC hardware. +**WARNING**: The procedures listed here are MUST DO in case of new hardware +first powerup. + ## Automated Self Test There is basic built-in integrity check. It is useful to do this the first time @@ -9,18 +12,34 @@ you power PMC up to make sure that hardware is ok. (pmc) pm_self_test -You can do it with or without motor connected. Ignore the appropriate error -notification when do it without motor connected. +This test does the following steps in this order: + +- Get current sensors zero drift and check it is within the acceptable range. +- Check actual bootstrap retention time and compare with configuration. +- Check the power stage responds to the control. +- Check measurement accuracy against the distortion introduced by PWM. + +You can do it with or without machine connected. Ignore the appropriate error +notification when do it without machine connected. ## Automated Self Adjust -The result of self-adjustment is also useful since it allows you to identify -abnormal deviations in measuring circuits. +The result of self-adjustment is also useful in diagnosis since it allows you +to identify abnormal deviations in measuring circuits. (pmc) pm_self_adjust -In case of motor connected you also check the current sensing circuit. Above -two procedures are must do in case of new hardware first powerup. +This adjustment does the following steps in this order: + +- Get current sensors zero drift and check it is within the acceptable range. +- Adjust the voltage measurement channels relatively to DC link voltage. +- Adjust dead-time distortion compensation (**OPTIONAL**). +- Adjust the current measurement channels pairwise. + +Note that in step 4 you need to connect the machine (or test coil) to let the +current flow in phase circuits. + +## See also Also look into [Trouble Shooting](TroubleShooting.md) page in case of you getting any error codes in `pm.fsm_errno`. diff --git a/doc/MachineProbe.md b/doc/MachineProbe.md index 4462cd2..9a7de2f 100644 --- a/doc/MachineProbe.md +++ b/doc/MachineProbe.md @@ -1,8 +1,10 @@ ## Overview This page describes how to identify the machine parameters by means of PMC. The -knowledge of parameters is necessary to control. Any new machine connected to -the PMC should be identified before run in closed control loop. +knowledge of parameters is necessary to control. + +**WARNING**: Any new machine connected to the PMC should be identified before +run in closed control loop. ## Preparation @@ -14,16 +16,16 @@ be aware. These parameters are used to probe the machine. There are a lot of parameters that can affect the machine identification. But we believe that they will need a change only in a complicated case. Most likely -you will need to decrease probe currents for a small machine. +you will need to decrease probing currents for a small machine. -* `pm.probe_current_hold`, `pm.probe_current_weak` - Two current setpoints that +- `pm.probe_current_hold`, `pm.probe_current_weak` - Two current setpoints that is used to estimate stator resistance. Please note they must be significantly - different to get accurate estimate. -* `pm.probe_freq_sine`, `pm.probe_current_sine` - Sine wave frequency and - amplitude that is used to estimate stator impedance. -* `pm.probe_speed_hold` - Speed setpoint for the initial spinup. At this speed + different to get accurate well-conditioned estimate. +- `pm.probe_freq_sine`, `pm.probe_current_sine` - Sine wave frequency and + amplitude that is used to estimate stator winding impedance. +- `pm.probe_speed_hold` - Speed setpoint for the initial spinup. At this speed flux linkage and noise threshold will be estimated. -* `pm.probe_loss_maximal` - Maximal heating losses on stator winding. This +- `pm.probe_loss_maximal` - Maximal heating losses on stator winding. This allows us to assume maximal machine current. Also pay attention to the forced control parameters which are used to achieve @@ -31,33 +33,32 @@ initial spinup. (pmc) reg pm.forced -* `pm.forced_hold_D` - Forced current setpoint which should be enough to hold +- `pm.forced_hold_D` - Forced current setpoint which should be enough to hold rotor in aligned position and force it turn. -* `pm.forced_accel` - Allowed acceleration of the forced control. +- `pm.forced_accel` - Allowed acceleration of the forced control. If you use power supply that not tolerate reverse current then consider the wattage limit settings. (pmc) reg pm.watt -* `pm.watt_wA_reverse` - Maximal reverse current on DC link. -* `pm.watt_uDC_maximal` - Maximal overvoltage on DC link. +- `pm.watt_wA_reverse` - Maximal reverse current on DC link. +- `pm.watt_uDC_maximal` - Maximal overvoltage on DC link. Also do not forget to reset the machine parameters if you have previously run -with another machine. +another machine. (pmc) pm_default_probe ## Sensors adjustment To achieve the best accuracy PMC has the ability of self-adjust voltage and -current onboard sensors. The automatic self-adjustment is necessary to match -the voltage measurement channels. Also current sensors will be self-adjusted if -machine is connected. +current onboard sensors. The self-adjustment procedure allows you to match +measurement channels between phases. (pmc) pm_self_adjust -This is enough to do it once and save the values in the flash. But we recommend +This is enough to do it once and store the values in the flash. But we recommend to do it again if you radically change DC link voltage. ## Number of the rotor pole pairs @@ -69,14 +70,14 @@ then divide it by 2. This is the most famous method. (pmc) reg pm.const_Zp If access to the machine is restricted and to count the magnets is impossible -then just leave a value 1. Instead of mechanical speed you will see electrical -speed. By measuring the mechanical speed directly you can estimate `Zp` and set -it later. +then you can leave a value 1. Instead of mechanical speed you will see +electrical speed. By independent measuring the mechanical speed you can +estimate `Zp` and set it later. ## Impedance of stator windings We measure the resistance `pm.const_Rs` by difference of voltage drop on two -values of holding current. For more accuracy you need to increase the probe +values of holding current. For more accuracy you need to increase the probing currents or reduce DC link voltage. Then we use a high frequency sinusoidal signal to measure the full impedance @@ -84,8 +85,8 @@ and calculate DQ inductances `pm.const_im_L1` and `pm.const_im_L2`. (pmc) pm_probe_impedance -If the procedure fails with an error sure that probe currents are suitable for -you machine. +If the procedure fails with an error code sure that probing currents are +suitable for your machine. ## Rotor flux linkage @@ -99,15 +100,16 @@ This parameter also known as `Kv` rating. Internal representation is ``` To identify `lambda` you have to run the machine. Also the rotor should rotate -at significant speed. We do a forced initial spinup to reach this condition. +at significant speed to get enough BEMF voltage. We do a forced initial spinup +to reach this condition. (pmc) pm_probe_spinup If the procedure fails to spinup the machine try to adjust forced control parameters. -To get more accurate flux linkage estimate you can run the machine at high -speed and request lambda probe manually. Do not load the machine. +To get a more accurate flux linkage estimate you can run the machine at high +speed and request lambda probing manually. Do not load the machine. (pmc) pm_fsm_startup (pmc) reg pm.s_setpoint_rpm @@ -116,7 +118,7 @@ speed and request lambda probe manually. Do not load the machine. ## No forced spinup If you failed to start the machine with `pm_probe_spinup` you have an option to -identify flux linkage in detached mode. You will have to rotate the machine +identify the flux linkage in detached mode. You will have to rotate the machine manually in this case. (pmc) pm_probe_detached @@ -125,8 +127,8 @@ PMC will wait for the machine to reach at least `pm.zone_threshold` speed. ## Speed noise threshold -After flux linkage we estimate speed noise to know the lower bound of flux -observer operation. As a result these threshold values are calculated. +After a flux linkage we estimate speed noise level to know the lower bound of +flux observer operation. As a result these threshold values are calculated. (pmc) reg pm.zone_noise (pmc) reg pm.zone_threshold @@ -136,11 +138,13 @@ observer operation. As a result these threshold values are calculated. Final estimate is a moment of inertia `pm.const_Ja`. To do this possible a speed maneuver will be performed. Note that this may result energy regeneration so your power supply must tolerate this. Either you should limit maximal DC -link current reverse. +link current reverse as stated above. This constant is used to tune speed control loop. Also it is used in operation to predict the speed changes from an applied current. +## See also + Also look into [Trouble Shooting](TroubleShooting.md) page in case of you getting any error codes in `pm.fsm_errno`. diff --git a/doc/TroubleShooting.md b/doc/TroubleShooting.md index f65db98..36fc941 100644 --- a/doc/TroubleShooting.md +++ b/doc/TroubleShooting.md @@ -87,4 +87,20 @@ Apparently temperature regulation by current limiting is not functional. `PM_ERROR_HW_EMERGENCY_STOP` - Emergency situation detected by emergency endstop signal. +## Log in volatile RAM + +In case of critical system error like a crystal clock failure or watchdog reset +this information will be logged in volatile RAM. You can also find timestamped +PMC error codes in the log. Note that contents of the log is erased if you +remove power from PMC. + +To print out and clear the log contents use these commands. + + (pmc) ap_log_flush + (pmc) ap_log_clean + +## See also + +Also look into [Integrity Self Test](IntegritySelfTest.md) page in case of you +if you need to check that your hardware is not broken. diff --git a/phobia/link.c b/phobia/link.c index 4bc49b7..880369d 100644 --- a/phobia/link.c +++ b/phobia/link.c @@ -183,6 +183,21 @@ lk_token(char **sp) return r; } +static char * +link_mballoc(struct link_pmc *lp, int len) +{ + struct link_priv *priv = lp->priv; + char *mb = NULL; + + if ((int) (priv->mbflow - priv->mb) < sizeof(priv->mb) - len) { + + mb = priv->mbflow; + priv->mbflow += len; + } + + return mb; +} + static int link_fetch_network(struct link_pmc *lp) { @@ -216,7 +231,6 @@ link_fetch_network(struct link_pmc *lp) static void link_reg_postproc(struct link_pmc *lp, struct link_reg *reg) { - struct link_priv *priv = lp->priv; double dval; if (lk_stoi(®->lval, reg->val) != NULL) { @@ -257,19 +271,22 @@ link_reg_postproc(struct link_pmc *lp, struct link_reg *reg) if ( (reg->mode & 7U) == LINK_REG_CONFIG && (reg->mode & LINK_REG_TYPE_INT) != 0 && strlen(reg->um) >= 7 - && reg->lval >= 0 && reg->lval < LINK_COMBO_MAX - && reg->combo[reg->lval] == NULL) { - - if ((int) (priv->mbflow - priv->mb) < sizeof(priv->mb) - 90U) { + && strlen(reg->um) < LINK_NAME_MAX + && reg->lval >= 0 + && reg->lval < LINK_COMBO_MAX) { - sprintf(priv->mbflow, "%.77s", reg->um); + if (reg->combo[reg->lval] == NULL) { - reg->combo[reg->lval] = priv->mbflow; - priv->mbflow += strlen(priv->mbflow) + 1; + reg->combo[reg->lval] = link_mballoc(lp, LINK_NAME_MAX); } - reg->lmax_combo = (reg->lval > reg->lmax_combo) - ? reg->lval : reg->lmax_combo; + if (reg->combo[reg->lval] != NULL) { + + sprintf(reg->combo[reg->lval], "%.77s", reg->um); + + reg->lmax_combo = (reg->lval > reg->lmax_combo) + ? reg->lval : reg->lmax_combo; + } } } diff --git a/phobia/phobia.c b/phobia/phobia.c index c6382ca..318356a 100644 --- a/phobia/phobia.c +++ b/phobia/phobia.c @@ -265,7 +265,13 @@ pub_contextual(struct public *pub, struct link_reg *reg, struct nk_rect bounds) /* TODO */ } else { - sprintf(pub->lbuf, "Update rate \"%i\"", reg->update); + if (reg->update != 0) { + + sprintf(pub->lbuf, "Update Rate = %i (ms)", reg->update); + } + else { + sprintf(pub->lbuf, "Update Disabled"); + } if (nk_contextual_item_label(ctx, pub->lbuf, NK_TEXT_LEFT)) { @@ -274,7 +280,7 @@ pub_contextual(struct public *pub, struct link_reg *reg, struct nk_rect bounds) if (reg->mode & LINK_REG_TYPE_FLOAT) { - sprintf(pub->lbuf, "* Range \"%.22s\" - \"%.22s\"", + sprintf(pub->lbuf, "* Range [%.22s; %.22s]", reg->vmin, reg->vmax); if (nk_contextual_item_label(ctx, pub->lbuf, NK_TEXT_LEFT)) { @@ -1804,7 +1810,7 @@ reg_float_um(struct public *pub, const char *sym, const char *name, int defsel) struct nk_style_edit edit; struct nk_color hidden; - int rc, min, max; + int rc, min_ID, max_ID; edit = ctx->style.edit; @@ -1816,16 +1822,33 @@ reg_float_um(struct public *pub, const char *sym, const char *name, int defsel) nk_layout_row_template_push_static(ctx, pub->fe_base * 2); nk_layout_row_template_end(ctx); - rc = link_reg_lookup_range(lp, sym, &min, &max); + if (sym[0] >= '0' && sym[0] <= '9' && sym[1] == '/') { - if (rc != 0 && max >= min) { + reg = link_reg_lookup(lp, sym + 2); - if (lp->reg[min + defsel].shown == 0) { + if (reg != NULL) { - lp->reg[min].um_sel = defsel; + rc = (int) (sym[0] - '1'); + + min_ID = (int) (reg - lp->reg); + max_ID = min_ID + rc; + } + else { + rc = 0; } + } + else { + rc = link_reg_lookup_range(lp, sym, &min_ID, &max_ID); + } - reg = &lp->reg[min + lp->reg[min].um_sel]; + if (rc != 0 && max_ID >= min_ID) { + + if (lp->reg[min_ID + defsel].shown == 0) { + + lp->reg[min_ID].um_sel = defsel; + } + + reg = &lp->reg[min_ID + lp->reg[min_ID].um_sel]; if (reg->fetched + 500 > lp->clock) { @@ -1857,17 +1880,17 @@ reg_float_um(struct public *pub, const char *sym, const char *name, int defsel) nk_spacer(ctx); - if (max != min) { + if (max_ID != min_ID) { rc = nk_combo_callback(ctx, ®_um_get_item, - &lp->reg[min], lp->reg[min].um_sel, - (max - min) + 1, pub->fe_font_h + 10, + &lp->reg[min_ID], lp->reg[min_ID].um_sel, + (max_ID - min_ID) + 1, pub->fe_font_h + 10, nk_vec2(pub->fe_base * 8, 400)); - if (rc != lp->reg[min].um_sel) { + if (rc != lp->reg[min_ID].um_sel) { - lp->reg[min].um_sel = rc; - lp->reg[min + lp->reg[min].um_sel].onefetch = 1; + lp->reg[min_ID].um_sel = rc; + lp->reg[min_ID + lp->reg[min_ID].um_sel].onefetch = 1; } } else { @@ -3063,6 +3086,8 @@ page_probe(struct public *pub) nk_layout_row_dynamic(ctx, 0, 1); nk_spacer(ctx); nk_spacer(ctx); + nk_spacer(ctx); + nk_spacer(ctx); } static void @@ -3842,9 +3867,9 @@ page_config(struct public *pub) reg_float(pub, "pm.probe_current_sine", "Probe sine current"); reg_float(pub, "pm.probe_current_bias", "Probe bias current"); reg_float(pub, "pm.probe_freq_sine", "Probe sine frequency"); - reg_float_um(pub, "pm.probe_speed_hold", "Probe speed", 0); - reg_float_um(pub, "pm.probe_speed_tol", "Speed settle tolerance", 0); - reg_float_um(pub, "pm.probe_location_tol", "Location settle tolerance", 0); + reg_float_um(pub, "pm.probe_speed_hold", "Probe speed", 1); + reg_float_um(pub, "pm.probe_speed_tol", "Settle speed tolerance", 1); + reg_float_um(pub, "pm.probe_location_tol", "Settle location tolerance", 0); reg_float(pub, "pm.probe_loss_maximal", "Maximal heating losses"); reg_float(pub, "pm.probe_gain_P", "Probe loop gain P"); reg_float(pub, "pm.probe_gain_I", "Probe loop gain I"); @@ -3934,9 +3959,9 @@ page_lu_forced(struct public *pub) reg_float(pub, "pm.forced_hold_D", "Forced hold current"); reg_float(pub, "pm.forced_weak_D", "Forced weak current"); - reg_float_um(pub, "pm.forced_maximal", "Maximal forward speed", 0); - reg_float_um(pub, "pm.forced_reverse", "Maximal reverse speed", 0); - reg_float_um(pub, "pm.forced_accel", "Forced acceleration", 0); + reg_float_um(pub, "pm.forced_maximal", "Maximal forward speed", 1); + reg_float_um(pub, "pm.forced_reverse", "Maximal reverse speed", 1); + reg_float_um(pub, "pm.forced_accel", "Forced acceleration", 1); reg_float(pub, "pm.forced_slew_rate", "Current slew rate"); reg_float(pub, "pm.forced_fall_rate", "Current fall rate"); reg_float(pub, "pm.forced_stop_DC", "Stop DC threshold"); @@ -4021,8 +4046,8 @@ page_lu_flux(struct public *pub) nk_layout_row_dynamic(ctx, 0, 1); nk_spacer(ctx); - reg_float_um(pub, "pm.zone_noise", "Noise threshold", 0); - reg_float_um(pub, "pm.zone_threshold", "Zone threshold", 0); + reg_float_um(pub, "pm.zone_noise", "Noise threshold", 1); + reg_float_um(pub, "pm.zone_threshold", "Zone threshold", 1); reg_float(pub, "pm.zone_gain_TH", "Zone hysteresis"); reg_float(pub, "pm.zone_gain_LP", "Zone gain LPF"); @@ -4071,7 +4096,7 @@ page_lu_flux(struct public *pub) reg_enum_errno(pub, "pm.lu_MODE", "LU operation mode", 0); reg_enum_errno(pub, "pm.flux_ZONE", "FLUX speed ZONE", 0); - reg_float_um(pub, "pm.flux_wS", "FLUX speed estimate", 0); + reg_float_um(pub, "pm.flux_wS", "FLUX speed estimate", 1); reg_float(pub, "pm.flux_lambda", "Flux linkage estimate"); reg_float(pub, "pm.kalman_bias_Q", "Q relaxation bias"); @@ -4474,10 +4499,8 @@ page_wattage(struct public *pub) nk_layout_row_dynamic(ctx, 0, 1); nk_spacer(ctx); - reg_float(pub, "pm.watt_wP_maximal", "Maximal consumption"); - reg_float(pub, "pm.watt_wA_maximal", "Maximal DC link current"); - reg_float(pub, "pm.watt_wP_reverse", "Maximal regeneration"); - reg_float(pub, "pm.watt_wA_reverse", "Maximal DC link reverse"); + reg_float_um(pub, "2/pm.watt_wP_maximal", "Maximal consumption", 1); + reg_float_um(pub, "2/pm.watt_wP_reverse", "Maximal regeneration", 1); reg_float(pub, "pm.watt_uDC_maximal", "DC link voltage HIGH"); reg_float(pub, "pm.watt_uDC_minimal", "DC link voltage LOW"); @@ -4629,9 +4652,9 @@ page_lp_speed(struct public *pub) nk_layout_row_dynamic(ctx, 0, 1); nk_spacer(ctx); - reg_float_um(pub, "pm.s_maximal", "Maximal forward speed", 0); - reg_float_um(pub, "pm.s_reverse", "Maximal reverse speed", 0); - reg_float_um(pub, "pm.s_accel", "Maximal acceleration", 0); + reg_float_um(pub, "pm.s_maximal", "Maximal forward speed", 1); + reg_float_um(pub, "pm.s_reverse", "Maximal reverse speed", 1); + reg_float_um(pub, "pm.s_accel", "Maximal acceleration", 1); nk_layout_row_dynamic(ctx, 0, 1); nk_spacer(ctx); @@ -5255,6 +5278,31 @@ page_flash(struct public *pub) nk_group_end(ctx); } + nk_layout_row_dynamic(ctx, 0, 1); + nk_spacer(ctx); + + nk_layout_row_template_begin(ctx, 0); + nk_layout_row_template_push_static(ctx, pub->fe_base * 2); + nk_layout_row_template_push_static(ctx, pub->fe_base * 2); + nk_layout_row_template_push_static(ctx, pub->fe_base * 1); + nk_layout_row_template_push_variable(ctx, 1); + nk_layout_row_template_end(ctx); + + nk_spacer(ctx); + pub_drawing_flash_colored(nk, 'a'); + nk_spacer(ctx); + nk_label(ctx, "Data block with correct CRC", NK_TEXT_LEFT); + + nk_spacer(ctx); + pub_drawing_flash_colored(nk, 'x'); + nk_spacer(ctx); + nk_label(ctx, "Garbage block", NK_TEXT_LEFT); + + nk_spacer(ctx); + pub_drawing_flash_colored(nk, '.'); + nk_spacer(ctx); + nk_label(ctx, "Erased block", NK_TEXT_LEFT); + if (lp->unable_warning[0] != 0) { strcpy(pub->popup_msg, lp->unable_warning); @@ -5289,7 +5337,7 @@ page_upgrade(struct public *pub) { nk_layout_row_dynamic(ctx, 0, 1); - if (nk_menu_item_label(ctx, "Embedded bootloader", NK_TEXT_LEFT)) { + if (nk_menu_item_label(ctx, "Enter bootloader", NK_TEXT_LEFT)) { if (lp->linked != 0) { diff --git a/src/hal/hal.c b/src/hal/hal.c index 07e9123..5c35eb6 100644 --- a/src/hal/hal.c +++ b/src/hal/hal.c @@ -6,6 +6,7 @@ #include "cmsis/stm32xx.h" #define HAL_FLAG_SIGNATURE 0x2A7CEA64U +#define HAL_TEXT_INC(np) (((np) < sizeof(log.text) - 1U) ? (np) + 1 : 0) uint32_t clock_cpu_hz; @@ -14,8 +15,8 @@ LOG_t log LD_NOINIT; typedef struct { - uint32_t bootload_flag; - uint32_t crystal_disabled; + uint32_t bootload_flag; + uint32_t crystal_disabled; } priv_HAL_t; @@ -380,45 +381,71 @@ void hal_memory_fence() int log_status() { - return (log.textbuf[0] != 0) ? HAL_FAULT : HAL_OK; + return ( log.boot_FLAG == HAL_FLAG_SIGNATURE + && log.text_wp != log.text_rp) ? HAL_FAULT : HAL_OK; } void log_bootup() { - if (log.boot_SIGNATURE != HAL_FLAG_SIGNATURE) { + if (log.boot_FLAG != HAL_FLAG_SIGNATURE) { - log.boot_SIGNATURE = HAL_FLAG_SIGNATURE; + log.boot_FLAG = HAL_FLAG_SIGNATURE; log.boot_COUNT = 0U; - memset(log.textbuf, 0, sizeof(log.textbuf)); - - log.textend = 0; + log.text_wp = 0; + log.text_rp = 0; } else { log.boot_COUNT += 1U; - - log.textbuf[sizeof(log.textbuf) - 1] = 0; } } void log_putc(int c) { - if (unlikely(log.boot_SIGNATURE != HAL_FLAG_SIGNATURE)) { + if (unlikely(log.boot_FLAG != HAL_FLAG_SIGNATURE)) { - log.boot_SIGNATURE = HAL_FLAG_SIGNATURE; - log.boot_COUNT = 0U; + log.boot_FLAG = HAL_FLAG_SIGNATURE; + + log.text_wp = 0; + log.text_rp = 0; + } + + log.text[log.text_wp] = (char) c; + + log.text_wp = HAL_TEXT_INC(log.text_wp); + log.text_rp = (log.text_rp == log.text_wp) + ? HAL_TEXT_INC(log.text_rp) : log.text_rp; +} + +void log_flush() +{ + int rp, wp; + + if (log.boot_FLAG == HAL_FLAG_SIGNATURE) { + + rp = log.text_rp; + wp = log.text_wp; - memset(log.textbuf, 0, sizeof(log.textbuf)); + while (rp != wp) { - log.textend = 0; + putc(log.text[rp]); + + rp = HAL_TEXT_INC(rp); + } + + puts(EOL); } - else if (unlikely( log.textend < 0 - || log.textend >= sizeof(log.textbuf) - 1U)) { +} + +void log_clean() +{ + if (unlikely(log.boot_FLAG != HAL_FLAG_SIGNATURE)) { - log.textend = 0; + log.boot_FLAG = HAL_FLAG_SIGNATURE; } - log.textbuf[log.textend++] = (char) c; + log.text_wp = 0; + log.text_rp = 0; } void DBGMCU_mode_stop() diff --git a/src/hal/hal.h b/src/hal/hal.h index 438b344..7697ff1 100644 --- a/src/hal/hal.h +++ b/src/hal/hal.h @@ -172,11 +172,12 @@ HAL_t; typedef struct { - uint32_t boot_SIGNATURE; + uint32_t boot_FLAG; uint32_t boot_COUNT; - char textbuf[2000]; - int textend; + char text[2000]; + int text_wp; + int text_rp; } LOG_t; @@ -203,6 +204,8 @@ void hal_memory_fence(); int log_status(); void log_bootup(); void log_putc(int c); +void log_flush(); +void log_clean(); void DBGMCU_mode_stop(); diff --git a/src/main.c b/src/main.c index 35be216..ab5100c 100644 --- a/src/main.c +++ b/src/main.c @@ -1005,7 +1005,10 @@ in_STEP_DIR() if (ap.step_STARTUP == PM_ENABLED) { - if (pm.lu_MODE == PM_LU_DISABLED) { + if ( pm.lu_MODE == PM_LU_DISABLED + && pm.fsm_errno == PM_OK) { + + ap.step_POS = 0; pm.fsm_req = PM_STATE_LU_STARTUP; } @@ -1147,7 +1150,7 @@ SH_DEF(ap_clock) printf("Clock %i %i" EOL, log.boot_COUNT, xTaskGetTickCount()); } -SH_DEF(ap_task_info) +SH_DEF(ap_dbg_task) { TaskStatus_t *list; int len, symStat, n; @@ -1204,7 +1207,7 @@ SH_DEF(ap_task_info) } } -SH_DEF(ap_heap_info) +SH_DEF(ap_dbg_heap) { HeapStats_t info; @@ -1225,26 +1228,7 @@ SH_DEF(ap_heap_info) info.xNumberOfSuccessfulFrees); } -SH_DEF(ap_log_flush) -{ - if (log_status() != HAL_OK) { - - puts(log.textbuf); - puts(EOL); - } -} - -SH_DEF(ap_log_clean) -{ - if (log_status() != HAL_OK) { - - memset(log.textbuf, 0, sizeof(log.textbuf)); - - log.textend = 0; - } -} - -SH_DEF(ap_hexdump) +SH_DEF(ap_dbg_hexdump) { uint8_t *maddr, mdata[16]; int sym, n, i, count = 4; @@ -1284,6 +1268,22 @@ SH_DEF(ap_hexdump) } } +SH_DEF(ap_log_flush) +{ + if (log_status() != HAL_OK) { + + log_flush(); + } +} + +SH_DEF(ap_log_clean) +{ + if (log_status() != HAL_OK) { + + log_clean(); + } +} + SH_DEF(ap_reboot) { if (pm.lu_MODE != PM_LU_DISABLED) { diff --git a/src/phobia/pm.c b/src/phobia/pm.c index 2f3768a..e5dc417 100644 --- a/src/phobia/pm.c +++ b/src/phobia/pm.c @@ -28,6 +28,8 @@ void pm_quick_build(pmc_t *pm) pm->quick_iWb = 1.f / pm->const_lambda; pm->quick_iWb2 = pm->quick_iWb * pm->quick_iWb; + + pm->flux_LINKAGE = PM_ENABLED; } if (pm->const_im_L1 > M_EPSILON) { @@ -1034,6 +1036,7 @@ pm_kalman_jacobian(pmc_t *pm, const float X[2], const float F[2], float wS) A[6] = (- F[0] * pm->vsi_X - F[1] * pm->vsi_Y) * pm->quick_TiL2; A[7] = (- pm->const_lambda - X[0] * pm->const_im_L1) * pm->quick_TiL2; A[8] = pm->quick_TiL2; + A[9] = pm->m_dT; } @@ -1770,8 +1773,8 @@ pm_lu_FSM(pmc_t *pm) m_rotatef(lu_F, - pm->lu_wS * pm->m_dT * 0.5f); - pm->lu_uD = pm->lu_F[0] * pm->tvm_X0 + pm->lu_F[1] * pm->tvm_Y0; - pm->lu_uQ = pm->lu_F[0] * pm->tvm_Y0 - pm->lu_F[1] * pm->tvm_X0; + pm->lu_uD = lu_F[0] * pm->tvm_X0 + lu_F[1] * pm->tvm_Y0; + pm->lu_uQ = lu_F[0] * pm->tvm_Y0 - lu_F[1] * pm->tvm_X0; /* Transfer to the next apriori position. * */ @@ -3443,7 +3446,7 @@ void pm_feedback(pmc_t *pm, pmfb_t *fb) A = pm->lu_F[0] * pm->flux_F[0] + pm->lu_F[1] * pm->flux_F[1]; B = pm->lu_F[1] * pm->flux_F[0] - pm->lu_F[0] * pm->flux_F[1]; - pm->d_flux_rsu = m_atan2f(B, A) * (180.f / M_PI_F); + pm->dbg_flux_rsu = m_atan2f(B, A) * (180.f / M_PI_F); } if (unlikely(m_isfinitef(pm->lu_F[0]) == 0)) { diff --git a/src/phobia/pm.h b/src/phobia/pm.h index 955e664..4b94d70 100644 --- a/src/phobia/pm.h +++ b/src/phobia/pm.h @@ -409,13 +409,13 @@ typedef struct { float forced_stop_DC; int flux_DETACH; + int flux_LINKAGE; int detach_TIM; float detach_threshold; float detach_trip_tol; float detach_gain_SF; - int flux_LINKAGE; int flux_TYPE; int flux_ZONE; @@ -600,7 +600,7 @@ typedef struct { float x_gain_P; float x_gain_D; - float d_flux_rsu; + float dbg_flux_rsu; void (* proc_set_DC) (int, int, int); void (* proc_set_Z) (int); diff --git a/src/phobia/pm_fsm.c b/src/phobia/pm_fsm.c index 9d13836..662728a 100644 --- a/src/phobia/pm_fsm.c +++ b/src/phobia/pm_fsm.c @@ -1582,7 +1582,6 @@ pm_fsm_state_lu_startup(pmc_t *pm, int in_ZONE) pm->forced_track_D = 0.f; pm->flux_DETACH = PM_DISABLED; - pm->detach_TIM = 0; if (pm->config_LU_ESTIMATE == PM_FLUX_NONE) { @@ -1592,14 +1591,19 @@ pm_fsm_state_lu_startup(pmc_t *pm, int in_ZONE) pm->flux_LINKAGE = PM_ENABLED; } - else if (pm->const_lambda < M_EPSILON) { + else if (pm->const_lambda > M_EPSILON) { - /* Here we indicate that flux linkage + pm->flux_LINKAGE = PM_ENABLED; + } + else { + /* So we indicate that flux linkage * is to be estimated further. * */ pm->flux_LINKAGE = PM_DISABLED; } + pm->detach_TIM = 0; + pm->flux_TYPE = PM_FLUX_NONE; pm->flux_ZONE = in_ZONE; @@ -1832,11 +1836,6 @@ pm_fsm_state_probe_const_flux_linkage(pmc_t *pm) pm->kalman_bias_Q = 0.f; pm_quick_build(pm); - - if (pm->flux_LINKAGE != PM_ENABLED) { - - pm->flux_LINKAGE = PM_ENABLED; - } } else { pm->fsm_errno = PM_ERROR_UNCERTAIN_RESULT; diff --git a/src/regdefs.h b/src/regdefs.h index ad85b02..4baee69 100644 --- a/src/regdefs.h +++ b/src/regdefs.h @@ -500,7 +500,7 @@ ID_PM_X_GAIN_P, ID_PM_X_GAIN_P_RADPS, ID_PM_X_GAIN_P_MMPS, ID_PM_X_GAIN_D, -ID_PM_D_FLUX_RSU, +ID_PM_DBG_FLUX_RSU, ID_TLM_RATE_GRAB, ID_TLM_RATE_LIVE, ID_TLM_MODE, diff --git a/src/regfile.c b/src/regfile.c index 17b9a5c..b26a518 100644 --- a/src/regfile.c +++ b/src/regfile.c @@ -1863,7 +1863,7 @@ const reg_t regfile[] = { REG_DEF(pm.forced_stop_DC,,, "%", "%1f", REG_CONFIG, ®_proc_percent, NULL), REG_DEF(pm.detach_threshold,,, "V", "%3f", REG_CONFIG, NULL, NULL), - REG_DEF(pm.detach_trip_tol,,, "V", "%2e", REG_CONFIG, NULL, NULL), + REG_DEF(pm.detach_trip_tol,,, "V", "%3f", REG_CONFIG, NULL, NULL), REG_DEF(pm.detach_gain_SF,,, "", "%2e", REG_CONFIG, NULL, NULL), REG_DEF(pm.flux_ZONE,,, "", "%0i", REG_READ_ONLY, NULL, ®_format_enum), @@ -2054,7 +2054,7 @@ const reg_t regfile[] = { REG_DEF(pm.x_gain_P, _mmps,, "mm/s2", "%1f", 0, ®_proc_x_accel_mm, NULL), REG_DEF(pm.x_gain_D,,, "", "%1f", REG_CONFIG, NULL, NULL), - REG_DEF(pm.d_flux_rsu,,, "", "%3f", REG_READ_ONLY, NULL, NULL), + REG_DEF(pm.dbg_flux_rsu,,, "deg", "%3f", REG_READ_ONLY, NULL, NULL), REG_DEF(tlm.rate_grab,,, "Hz", "%1f", REG_CONFIG, ®_proc_tlm_rate, NULL), REG_DEF(tlm.rate_live,,, "Hz", "%1f", REG_CONFIG, ®_proc_tlm_rate, NULL), diff --git a/src/shdefs.h b/src/shdefs.h index d59efc7..2b241b1 100644 --- a/src/shdefs.h +++ b/src/shdefs.h @@ -3,11 +3,11 @@ SH_DEF(flash_info) SH_DEF(flash_wipe) SH_DEF(ap_version) SH_DEF(ap_clock) -SH_DEF(ap_task_info) -SH_DEF(ap_heap_info) +SH_DEF(ap_dbg_task) +SH_DEF(ap_dbg_heap) +SH_DEF(ap_dbg_hexdump) SH_DEF(ap_log_flush) SH_DEF(ap_log_clean) -SH_DEF(ap_hexdump) SH_DEF(ap_reboot) SH_DEF(ap_bootload) SH_DEF(pm_probe_impedance)