Motor Driver Evaluation Kit NEVB-MTR1-t01-1.3.1
Firmware for NEVB-MTR1-KIT1 for trapezoidal control of BLDC motors using Hall-effect sensors
Loading...
Searching...
No Matches
main.ino File Reference

Motor control implementation. More...

#include "config.h"
#include "tables.h"
#include "fault.h"
#include "filter.h"
#include "scpi.h"
Include dependency graph for main.ino:

Go to the source code of this file.

Functions

volatile motorflags_t motorFlags __attribute__ ((address(0x4A)))
 Motor control flags placed in I/O space for fast access.
 
volatile faultflags_t faultFlags __attribute__ ((address(0x3E)))
 Fault flags placed in I/O space for fast access.
 
void setup (void)
 Main initialization function.
 
void loop ()
 Main Loop Function.
 
static void FlagsInit (void)
 Initializes motorFlags and faultFlags.
 
static void ConfigsInit (void)
 Initializes motorConfigs.
 
static void PLLInit (void)
 Initialize PLL (Phase-Locked Loop)
 
static void PortsInit (void)
 Initialize I/O port directions and pull-up resistors.
 
void TimersInit (void)
 Initializes and synchronizes Timers.
 
static void PinChangeIntInit (void)
 Initialize pin change interrupts.
 
static void ADCInit (void)
 Initializes the ADC.
 
static uint16_t ADCSingleConversion (void)
 Perform a single ADC conversion.
 
static void EnableUpdate (void)
 Check whether the enable pin is set and update flags accordingly.
 
static void DisableMotor (void)
 Disable motor.
 
static void RemoteUpdate (void)
 Check whether the remote pin is set and update flags accordingly.
 
static void SpeedController (void)
 Speed regulator loop.
 
static void FatalError ()
 Handle a fatal error and enter a fault state.
 
static __attribute__ ((always_inline)) void SetDuty(const uint16_t duty)
 Set duty cycle for TIM4.
 
 if (direction==0)
 
 ClearPWMPorts ()
 
TCCR4E & DisablePWMOutputs ()
 
 EnablePWMOutputs ()
 

Variables

volatile motorconfigs_t motorConfigs
 Motor Configs.
 
volatile uint16_t commutationTicks = 0
 The number of 'ticks' between two hall sensor changes (counter).
 
volatile uint16_t lastCommutationTicks = 0xffff
 The number of 'ticks' between two hall sensor changes (store).
 
volatile uint8_t speedInput = 0
 The most recent "speed" input measurement.
 
volatile uint8_t speedOutput = 0
 The most recent "speed" output from the speed controller.
 
volatile uint16_t ibus = 0
 Hi-side Current (IBUS) measurement (Register Value).
 
volatile int16_t iphaseU = 0
 In-line Phase U current current measurement (Register Value).
 
volatile int16_t iphaseV = 0
 In-line Phase V current current measurement (Register Value).
 
volatile int16_t iphaseW = 0
 In-line Phase W current current measurement (Register Value).
 
volatile uint16_t vbusVref = 0
 VBUS voltage measurement (Register Value)
 
static uint8_t hall
 
 else
 
 tableAddress = (hall * 4)
 
 PORTB = (uint8_t)pgm_read_byte_near(tableAddress++)
 
 PORTC = (uint8_t)pgm_read_byte_near(tableAddress++)
 
 PORTD = (uint8_t)pgm_read_byte_near(tableAddress++)
 
 TCCR4E = (uint8_t)pgm_read_byte_near(tableAddress)
 

Detailed Description

Motor control implementation.

This file contains the full implementation of the motor control, except the PID-controller, filter, fault, SCPI and table implementations and definitions.

User Manual:
ANxxx: Trapezoidal Control of BLDC Motors Using Hall Effect Sensors
Documentation
For comprehensive code documentation, supported compilers, compiler settings and supported devices see readme.html
Author
Nexperia: http://www.nexperia.com
Support Page
For additional support, visit: https://www.nexperia.com/support
Author
Aanas Sayed
Date
2024/03/08


Definition in file main.ino.

Function Documentation

◆ __attribute__() [1/3]

volatile faultflags_t faultFlags __attribute__ ( (address(0x3E)) )

Fault flags placed in I/O space for fast access.

This variable contains all the flags used for faults. It is placed in GPIOR0 register, which allows usage of several fast bit manipulation/branch instructions.

Warning
This variable can only have a maximum size of 1 byte.

◆ __attribute__() [2/3]

volatile motorflags_t motorFlags __attribute__ ( (address(0x4A)) )

Motor control flags placed in I/O space for fast access.

This variable contains all the flags used for motor control. It is placed in GPIOR1 and GPIOR2 registers, which allows usage of several fast bit manipulation/branch instructions.

Warning
This variable can only have a maximum size of 2 bytes.

◆ __attribute__() [3/3]

static __attribute__ ( (always_inline) ) const
inlinestatic

Set duty cycle for TIM4.

Update the global actual direction flag based on the two latest hall values.

Updates global desired direction flag.

Read the hall sensor inputs and decode the hall state.

Perform block commutation based on direction and hall sensor input.

Wait for the start of the next PWM cycle.

Configures timers for block commutation.

This function sets the duty cycle for block commutation, where the duty range is 0-1023 (not in percentage). To convert to percentage, use: duty * 100 / 1023.

Parameters
dutyNew duty cycle, range 0-1023.

This function is called every time the drive waveform is changed and block commutation is needed. PWM outputs are safely disabled while configuration registers are changed to avoid unintended driving or shoot-through.

The function sets the PWM pins to input (High-Z) while changing modes and configures the timers. The output duty cycle is set to zero initially. It waits for the next PWM cycle to ensure that all outputs are updated, and then the motor drive waveform is set to block commutation. Finally, the PWM pins are changed back to output mode to allow PWM control.

This function waits for the beginning of the next PWM cycle to ensure smooth transitions between different PWM modes and avoid shoot-through conditions.

This function performs block commutation according to the specified direction of rotation and the hall sensor input. Block commutation is used to control motor phases during operation.

Parameters
directionDirection of rotation (DIRECTION_FORWARD or DIRECTION_REVERSE).
hallHall sensor input value corresponding to the rotor position.

This function reads the hall sensor inputs and converts them into a number ranging from 1 to 6, where the hall sensors' states are represented as bits: H3|H2|H1.

Returns
The decoded hall sensor value.
Return values
0Illegal hall state. Possible hardware error.
1-6Valid hall sensor values.
7Illegal hall state. Possible hardware error.

Running this function triggers a reading of the direction input pin. The desiredDirection flag is set accordingly.

Calling this function with the last two hall sensor values as parameters triggers an update of the global actualDirection flag.

Parameters
lastHallThe previous hall sensor value.
newHallThe current hall sensor value.

Definition at line 817 of file main.ino.

818{
819 TC4H = duty >> 8;
820 OCR4A = 0xFF & duty;
821}

◆ ADCInit()

static void ADCInit ( void )
static

Initializes the ADC.

This function initializes the ADC for speed reference, current and gate voltage measurements.

The function performs self-tests to ensure the ADC's accuracy:

  • It measures 0V to verify the ADC's ability to read close to zero.
  • It measures 1.1V to ensure the ADC's accuracy within a specified range.
  • It measures BREF and waits for any board to be connected.

If any of the self-tests fail, a fatal error is indicated.

After self-testing, the ADC is configured for speed reference measurements and set to trigger on ADC_TRIGGER.

Note
ADC_TRIGGER is set to ADC_TRIGGER_TIMER0_OVF. This triggers the ADC at a rate of ~977 samples per second. The ADC prescaler is set to ADC_PRESCALER_DIV_128 as this gives a 125kHz ADC clock. It is recommended to have the ADC clock between 50kHz and 200kHz to get maximum ADC resolution.
See also
ADC_TRIGGER

Definition at line 536 of file main.ino.

537{
538#if (WAIT_FOR_BOARD == TRUE)
539 // Select initial AD conversion channel [IBUS] to check if board is connected.
540 ADMUX = (ADC_REFERENCE_VOLTAGE | (1 << ADLAR) | ADC_MUX_L_IBUS);
541 ADCSRB = ADC_MUX_H_IBUS;
542 _delay_ms(1);
543
544 // Enable ADC
545 ADCSRA = (1 << ADEN);
546
547 // Start ADC single conversion and discard first measurement.
548 uint16_t adc_reading = ADCSingleConversion();
549
550 // Enable pull up resistor
551 PORTF |= (1 << IBUS_PIN);
552
553 _delay_ms(10);
555
556 // Start ADC single conversion to measure BREF.
557 adc_reading = ADCSingleConversion();
558
559 // Wait to check if any board is connected. Should be less than
560 // 0x3C0 if the inverter board is connected
561 while (adc_reading > 0x3C0)
562 {
564
565 // Start ADC single conversion to measure BREF.
566 adc_reading = ADCSingleConversion();
567
568 _delay_ms(10);
569 }
570
571 // Disable pull up resistor
572 PORTF &= ~(1 << IBUS_PIN);
573
574 _delay_ms(10);
575
576#else
577 // Select AD reference voltage and left adjust result.
578 ADMUX = (ADC_REFERENCE_VOLTAGE | (1 << ADLAR));
579
581#endif
582
583 // Re-initialize ADC mux channel select.
584 ADMUX &= ~ADC_MUX_L_BITS;
585 ADMUX |= ADC_MUX_L_SPEED;
586 // Set trigger source to ADC_TRIGGER.
587 ADCSRB = ADC_MUX_H_SPEED | ADC_TRIGGER;
588
589 // Re-initialize ADC to work with interrupts.
590 ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (1 << ADIF) | (1 << ADIE) | ADC_PRESCALER;
591}
void SweepLEDsBlocking(void)
Sweeps through all LEDs individually with a delay.
Definition fault.cpp:144
#define ADC_MUX_L_BITS
Lower ADC channel selection bits (MUX4:0) mask.
Definition config.h:1057
#define ADC_MUX_L_IBUS
Lower analog channel selection bits (MUX4:0) for motor current measurement.
Definition config.h:809
#define ADC_MUX_L_SPEED
Definition config.h:804
#define ADC_TRIGGER
ADC trigger used in this application.
Definition config.h:835
#define IBUS_PIN
IBUS ADC input pin (used to check if board is attached).
Definition config.h:845
#define ADC_MUX_H_IBUS
High analog channel selection bit (MUX5) for for motor current measurement.
Definition config.h:811
#define ADC_PRESCALER
ADC clock pre-scaler used in this application.
Definition config.h:831
#define ADC_MUX_H_SPEED
Definition config.h:807
#define ADC_REFERENCE_VOLTAGE
ADC voltage reference used in this application.
Definition config.h:833
static uint16_t ADCSingleConversion(void)
Perform a single ADC conversion.
Definition main.ino:600
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ADCSingleConversion()

static uint16_t ADCSingleConversion ( void )
static

Perform a single ADC conversion.

This function initiates a single ADC conversion to measure a voltage. It waits for the conversion to complete and then reads the ADC result.

Returns
The 16-bit ADC result representing the measured voltage.

Definition at line 600 of file main.ino.

601{
602 // Initialize ADC for one-time conversion.
603 ADCSRA |= (1 << ADSC);
604
605 // Wait for the conversion to complete.
606 while (ADCSRA & (1 << ADSC))
607 {
608 // Wait until the conversion is finished.
609 }
610
611 // Read the ADC result and combine ADCH and ADCL into a 16-bit value.
612 uint16_t value = (ADCL >> 6);
613 value |= 0x3ff & (ADCH << 2);
614
615 return value;
616}
Here is the caller graph for this function:

◆ ConfigsInit()

static void ConfigsInit ( void )
static

Initializes motorConfigs.

This function initializes motorConfigs to their default values.

Definition at line 366 of file main.ino.

367{
368 motorConfigs.tim4Freq = (uint32_t)F_MOSFET;
369 motorConfigs.tim4Top = (uint16_t)TIM4_TOP(motorConfigs.tim4Freq);
370 motorConfigs.tim4DeadTime = (uint16_t)DEAD_TIME;
371 motorConfigs.speedInputSource = (uint8_t)SPEED_INPUT_SOURCE_LOCAL;
372}
#define TIM4_TOP(tim4Freq)
Definition config.h:1302
#define SPEED_INPUT_SOURCE_LOCAL
Speed input source - Local or speed input pin.
Definition config.h:849
#define F_MOSFET
Desired Switching Frequency for MOSFET Gate Signals.
Definition config.h:157
#define DEAD_TIME
Dead Time Specification.
Definition config.h:186
volatile motorconfigs_t motorConfigs
Motor Configs.
Definition main.ino:66
Here is the caller graph for this function:

◆ DisableMotor()

static void DisableMotor ( void )
static

Disable motor.

This function disables the motor by clearing the enable flag and performing specific actions based on the TURN_OFF_MODE configuration:

Note
The behavior of this function depends on the TURN_OFF_MODE configuration.
See also
TURN_OFF_MODE

Definition at line 659 of file main.ino.

660{
661 motorFlags.enable = FALSE;
662 SetFaultFlag(FAULT_MOTOR_STOPPED, FALSE);
663
664#if (TURN_OFF_MODE == TURN_OFF_MODE_COAST)
665 // Disable driver signals to let the motor coast.
666 motorFlags.driveWaveform = WAVEFORM_UNDEFINED;
667 DisablePWMOutputs();
668 ClearPWMPorts();
669#endif
670}
#define WAVEFORM_UNDEFINED
Waveform status flag used for coasting.
Definition config.h:865
#define FALSE
FALSE constant value.
Definition config.h:745
@ FAULT_MOTOR_STOPPED
Is motor stopped?
Definition config.h:1248
Here is the caller graph for this function:

◆ EnableUpdate()

static void EnableUpdate ( void )
static

Check whether the enable pin is set and update flags accordingly.

This function checks the state of the enable pin and updates the motorFlags and faultFlags accordingly. If the enable pin is not set, it can perform specific actions based on the TURN_OFF_MODE configuration:

Note
The behavior of this function depends on the TURN_OFF_MODE configuration.
See also
TURN_OFF_MODE

Definition at line 633 of file main.ino.

634{
635 if ((PIND & (1 << ENABLE_PIN)) != 0)
636 {
637 motorFlags.enable = TRUE;
638 }
639 else
640 {
641 DisableMotor();
642 }
643}
#define ENABLE_PIN
Enable input pin.
Definition config.h:841
#define TRUE
TRUE constant value, defined to be compatible with comparisons.
Definition config.h:747
static void DisableMotor(void)
Disable motor.
Definition main.ino:659
Here is the call graph for this function:
Here is the caller graph for this function:

◆ FatalError()

static void FatalError ( )
static

Handle a fatal error and enter a fault state.

This function is called in response to a fatal error condition. It performs the following actions:

  • Sets the motor to stop rotation.
  • Once the motor is stopped, it will loop indefinitely inside CommutationTicksUpdate().

Definition at line 799 of file main.ino.

800{
801 // Stop the motor.
802 DisableMotor();
803
804 // Once this is set no more faults will be registered creating a snapshot
805 // of the failure point.
806 motorFlags.fatalFault = TRUE;
807}
Here is the call graph for this function:

◆ FlagsInit()

static void FlagsInit ( void )
static

Initializes motorFlags and faultFlags.

This function initializes both motorFlags and faultFlags to their default values.

Definition at line 339 of file main.ino.

340{
341 // Initialize motorFlags with default values.
342 motorFlags.speedControllerRun = FALSE;
343 motorFlags.remote = FALSE;
344 motorFlags.enable = FALSE;
345 motorFlags.actualDirection = DIRECTION_UNKNOWN;
346 motorFlags.desiredDirection = DIRECTION_FORWARD;
347 motorFlags.driveWaveform = WAVEFORM_UNDEFINED;
348 motorFlags.fatalFault = FALSE;
349
350 // Initialize faultFlags with default values. Set motorStopped to FALSE at
351 // startup. This will make sure that the motor is not started if it is not
352 // really stopped. If it is stopped, this variable will quickly be updated.
353 faultFlags.motorStopped = FALSE;
354 faultFlags.reverseDirection = FALSE;
355 faultFlags.overCurrent = FALSE;
356 faultFlags.noHallConnections = FALSE;
357 faultFlags.userFlag1 = FALSE;
358 faultFlags.userFlag2 = FALSE;
359 faultFlags.userFlag3 = FALSE;
360}
#define DIRECTION_FORWARD
Forward direction flag value.
Definition config.h:785
#define DIRECTION_UNKNOWN
Unknown direction flag value.
Definition config.h:789
Here is the caller graph for this function:

◆ if()

if ( direction = = 0)

Definition at line 887 of file main.ino.

888 {
889 tableAddress = blockCommutationTableForward;
890 }
const uint8_t blockCommutationTableForward[32]
Block Commutation Port Direction Masks for Forward Driving.
Definition tables.h:80

◆ loop()

void loop ( )

Main Loop Function.

The main loop function is executed continuously in normal operation after the program has configured everything. It continually checks if the speed controller needs to be run.

Definition at line 321 of file main.ino.

322{
323 if (motorFlags.remote == TRUE)
324 {
325 ScpiInput(Serial);
326 }
327 if (motorFlags.speedControllerRun)
328 {
330 motorFlags.speedControllerRun = FALSE;
331 }
332}
static void SpeedController(void)
Speed regulator loop.
Definition main.ino:722
void ScpiInput(Stream &interface)
Processes incoming data from a serial interface for SCPI commands.
Definition scpi.cpp:122
Here is the call graph for this function:

◆ PinChangeIntInit()

static void PinChangeIntInit ( void )
static

Initialize pin change interrupts.

This function initializes pin change interrupt on hall sensor input pins input, shutdown input and motor direction control input.

Definition at line 500 of file main.ino.

501{
502 // Initialize external interrupt on shutdown pin (INT0) and direction input
503 // (INT2) pin.
504 EICRA = (0 << ISC21) | (1 << ISC20) | (0 << ISC01) | (1 << ISC00);
505 EIMSK = (1 << INT2) | (1 << INT0);
506
507 // Initialize pin change interrupt on hall sensor inputs (PCINT1..3).
508 PCMSK0 = (1 << PCINT3) | (1 << PCINT2) | (1 << PCINT1);
509
510 // Enable pin change interrupt on ports with pin change signals
511 PCICR = (1 << PCIE0);
512}
Here is the caller graph for this function:

◆ PLLInit()

static void PLLInit ( void )
static

Initialize PLL (Phase-Locked Loop)

This function configures and initializes the PLL for clock generation. It sets the PLL frequency control register and waits until the PLL is locked and stable before returning.

Definition at line 381 of file main.ino.

382{
383 // Configure PLL Frequency Control Register to output 48MHz for USB Module and
384 // 64MHz for the High-Speed Clock Timer with a base speed of 96MHz for PLL
385 // Output Frequency.
386
387 PLLFRQ = (0 << PINMUX) | (1 << PLLUSB) | PLL_POSTSCALER_DIV_1_5 | (1 << PDIV3) | (0 << PDIV2) | (1 << PDIV1) | (0 << PDIV0);
388
389 // Enable PLL.
390 PLLCSR = (1 << PINDIV) | (1 << PLLE);
391
392 // Wait until PLOCK bit is set, indicating PLL is locked and stable.
393 while ((PLLCSR & (1 << PLOCK)) == 0)
394 {
395 // Wait for PLL lock
396 ;
397 }
398}
#define PLL_POSTSCALER_DIV_1_5
PLL Post-scaler - division factor 1.5.
Definition config.h:987
Here is the caller graph for this function:

◆ PortsInit()

static void PortsInit ( void )
static

Initialize I/O port directions and pull-up resistors.

This function initializes all I/O ports with the correct directions and enables pull-up resistors, if needed, for various pins and signals used in the motor control.

Definition at line 407 of file main.ino.

408{
409#if (EMULATE_HALL == TRUE)
410 // Configure and set hall sensor pins for motor emulation
411 PORTB &= ~((1 << H1_PIN) | (1 << H2_PIN) | (1 << H3_PIN));
412 PORTB |= (0x07 & pgm_read_byte_near(&expectedHallSequenceForward[1]));
413 // Set hall sensor pins as outputs.
414 DDRB |= (1 << H1_PIN) | (1 << H2_PIN) | (1 << H3_PIN);
415#endif
416
417#if ((HALL_PULLUP_ENABLE == TRUE) && (EMULATE_HALL != TRUE))
418 // Configure and set hall sensor pins as input with pull-ups enabled
419 PORTB |= (1 << H1_PIN) | (1 << H2_PIN) | (1 << H3_PIN);
420#endif
421
422 // Configure and set pins FAULT_PIN_3, FAULT_PIN_2, and FAULT_PIN_1 as outputs
423 PORTB &= ~((1 << FAULT_PIN_3) | (1 << FAULT_PIN_2));
424 DDRB |= (1 << FAULT_PIN_3) | (1 << FAULT_PIN_2);
425 PORTD &= ~(1 << FAULT_PIN_1);
426 DDRD |= (1 << FAULT_PIN_1);
427
428 // If remote mode, set enable and direction pin as output to allow software
429 // triggered interrupts
430 if (motorFlags.remote == TRUE)
431 {
432 PORTD &= ~((1 << ENABLE_PIN) | (1 << DIRECTION_COMMAND_PIN));
433 DDRD |= (1 << ENABLE_PIN) | (1 << DIRECTION_COMMAND_PIN);
434 }
435}
#define H2_PIN
Pin where H2 is connected.
Definition config.h:797
#define FAULT_PIN_2
Fault Pin 2.
Definition config.h:857
#define DIRECTION_COMMAND_PIN
Pin where direction command input is located.
Definition config.h:839
#define FAULT_PIN_3
Fault Pin 3.
Definition config.h:859
#define H3_PIN
Pin where H3 is connected.
Definition config.h:799
#define H1_PIN
Pin where H1 is connected.
Definition config.h:795
#define FAULT_PIN_1
Fault Pin 1.
Definition config.h:855
const uint8_t expectedHallSequenceForward[7]
Table of Expected Hall Sensor Values in Forward Direction.
Definition tables.h:149
Here is the caller graph for this function:

◆ RemoteUpdate()

static void RemoteUpdate ( void )
static

Check whether the remote pin is set and update flags accordingly.

This function checks the state of the remote pin and updates the motorFlags.

Note
This is only called during setup so any further pin changes are not detected.

Definition at line 679 of file main.ino.

680{
681 if ((PIND & (1 << REMOTE_PIN)) != 0)
682 {
683 motorFlags.remote = TRUE;
684 }
685 else
686 {
687 motorFlags.remote = FALSE;
688 }
689}
#define REMOTE_PIN
Remote input pin.
Definition config.h:843
Here is the caller graph for this function:

◆ setup()

void setup ( void )

Main initialization function.

The main initialization function initializes all subsystems needed for motor control.

Definition at line 267 of file main.ino.

268{
269 // Load motor configs
270 ConfigsInit();
271
272 // Initialize flags.
273 FlagsInit();
274
275 // Check if remote mode requested.
276 RemoteUpdate();
277
278 // Initialize peripherals.
279 PortsInit(); // depends on motorFlags.remote
280 ADCInit(); // include self-test + loop until board detected must be before TimersInit
281 PLLInit();
282 TimersInit();
283
284#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
285 PIDInit(PID_K_P, PID_K_I, PID_K_D, &pidParameters);
286#endif
287
288 if (motorFlags.remote == TRUE)
289 {
290 // Start serial interface with 115200 bauds.
291 Serial.begin(115200);
292 // while (!Serial); // wait for serial to finish initializing
293
294 // Initialise SCPI subsystem if remote mode.
295 ScpiInit();
296 }
297 else
298 {
299 // Update direction before enable flag.
300 DesiredDirectionUpdate();
301 // Do not update enable flag until everything is ready.
302 EnableUpdate();
303 }
304
305 // Set up pin change interrupts.
307
308 // Enable Timer4 overflow event interrupt.
309 TIMSK4 |= (1 << TOIE4);
310
311 // Enable interrupts globally and let motor driver take over.
312 sei();
313}
#define PID_K_P
PID Controller Proportional Gain Constant (Only for Closed Loop)
Definition config.h:509
#define PID_K_D
PID Controller Derivative Gain Constant (Only for Closed Loop)
Definition config.h:566
#define PID_K_I
PID Controller Integral Gain Constant (Only for Closed Loop)
Definition config.h:528
static void PortsInit(void)
Initialize I/O port directions and pull-up resistors.
Definition main.ino:407
static void ADCInit(void)
Initializes the ADC.
Definition main.ino:536
static void FlagsInit(void)
Initializes motorFlags and faultFlags.
Definition main.ino:339
static void PinChangeIntInit(void)
Initialize pin change interrupts.
Definition main.ino:500
static void PLLInit(void)
Initialize PLL (Phase-Locked Loop)
Definition main.ino:381
void TimersInit(void)
Initializes and synchronizes Timers.
Definition main.ino:455
static void EnableUpdate(void)
Check whether the enable pin is set and update flags accordingly.
Definition main.ino:633
static void ConfigsInit(void)
Initializes motorConfigs.
Definition main.ino:366
static void RemoteUpdate(void)
Check whether the remote pin is set and update flags accordingly.
Definition main.ino:679
void PIDInit(int16_t p_factor, int16_t i_factor, int16_t d_factor, pidData_t *pid)
Initialisation of PID controller parameters.
Definition pid.cpp:33
void ScpiInit(void)
Initializes the SCPI command parser and registers all supported commands.
Definition scpi.cpp:71
Here is the call graph for this function:

◆ SpeedController()

static void SpeedController ( void )
static

Speed regulator loop.

This function is called periodically every SPEED_CONTROLLER_TIME_BASE ticks. In this implementation, a simple PID controller loop is called, but this function could be replaced by any speed or other regulator.

If the SPEED_CONTROL_METHOD is set to SPEED_CONTROL_CLOSED_LOOP, a PID controller is used to regulate the speed. The speed input is converted into an increment set point, and a PID controller computes the output value. The output is limited to a maximum value of PID_OUTPUT_MAX.

If the SPEED_CONTROL_METHOD is not set to SPEED_CONTROL_CLOSED_LOOP, a simple speed control mechanism is applied. If the motor is enabled, the function calculates the delta between the speed input and the current speed output. If the delta exceeds the maximum allowed change, it limits the change to SPEED_CONTROLLER_MAX_DELTA. If the motor is disabled, the speed output is set to 0.

Before running the regulator, the function checks vbusVref against VBUS_MIN_THRESHOLD. If VBUS is below the threshold (e.g. motor power supply not yet applied), the PID integrator is reset, speedOutput is held at zero, and the function returns immediately. This prevents integrator wind-up and unintended drive output at startup.

Note
The behavior of this function depends on the SPEED_CONTROL_METHOD configuration.
See also
SPEED_CONTROL_METHOD, SPEED_CONTROLLER_TIME_BASE, SPEED_CONTROLLER_MAX_DELTA, SPEED_CONTROLLER_MAX_SPEED, PID_K_P, PID_K_I, PID_K_D_ENABLE, PID_K_D, PID_OUTPUT_MAX, VBUS_MIN_THRESHOLD

Definition at line 722 of file main.ino.

723{
724 if (motorFlags.enable == TRUE)
725 {
726 // Inhibit drive output if VBUS is not sufficiently powered. This prevents
727 // PID integrator wind-up and unintended PWM when the motor power rail is
728 // absent at startup.
730 {
731#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
732 PIDResetIntegrator(&pidParameters);
733#endif
734 speedOutput = 0;
735 return;
736 }
737
738#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
739 // Calculate an increment set point from the analog speed input.
740 int16_t incrementSetpoint = ((int32_t)speedInput * SPEED_CONTROLLER_MAX_SPEED) / SPEED_CONTROLLER_MAX_INPUT;
741
742 // PID regulator with feed forward from speed input.
743 uint16_t outputValue;
744
745 outputValue = PIDController(incrementSetpoint, (motorConfigs.tim4Freq / (lastCommutationTicks * 3)) >> 1, &pidParameters);
746
747 if (outputValue > PID_OUTPUT_MAX)
748 {
749 outputValue = PID_OUTPUT_MAX;
750 }
751
752 speedOutput = outputValue;
753
754 // Without the delay PID does not reset when needed
755 _delay_us(1);
756#else
757 // Calculate the delta in speedInput
758 int16_t delta = speedInput - speedOutput;
759 // If delta exceeds the maximum allowed change, limit it and update
760 // speedOutput
761 if (delta > SPEED_CONTROLLER_MAX_DELTA)
762 {
764 }
765 else if (delta < -SPEED_CONTROLLER_MAX_DELTA)
766 {
768 }
769 else
770 {
772 }
773#endif
774 }
775 else
776 {
777 if (speedOutput > 0)
778 {
780 {
782 }
783 else
784 {
785 speedOutput = 0;
786 }
787 }
788 }
789}
#define SPEED_CONTROLLER_MAX_INPUT
Maximum Speed Reference Input.
Definition config.h:891
#define VBUS_MIN_THRESHOLD
Minimum VBUS Threshold for Motor Operation (Register Value)
Definition config.h:692
#define SPEED_CONTROLLER_MAX_DELTA
Speed Controller Maximum Delta (Applicable for Open Loop Control)
Definition config.h:469
#define PID_OUTPUT_MAX
Maximum PID Controller Output (Only for Closed Loop)
Definition config.h:615
#define SPEED_CONTROLLER_MAX_SPEED
Speed Controller Maximum Speed.
Definition config.h:490
volatile uint16_t vbusVref
VBUS voltage measurement (Register Value)
Definition main.ino:255
volatile uint8_t speedInput
The most recent "speed" input measurement.
Definition main.ino:101
volatile uint8_t speedOutput
The most recent "speed" output from the speed controller.
Definition main.ino:108
volatile uint16_t lastCommutationTicks
The number of 'ticks' between two hall sensor changes (store).
Definition main.ino:94
uint16_t PIDController(int16_t setPoint, int16_t processValue, pidData_t *pid_st)
PID control algorithm.
Definition pid.cpp:56
void PIDResetIntegrator(pidData_t *pid_st)
Resets the integrator in the PID regulator.
Definition pid.cpp:131
Here is the call graph for this function:
Here is the caller graph for this function:

◆ TimersInit()

void TimersInit ( void )

Initializes and synchronizes Timers.

This function sets the correct pre-scaler and starts all required timers.

Timer 1 is used to trigger the fault multiplexing on overflow. Timer 3 is used, if EMULATE_HALL is set, to trigger the change in hall output on overflow. Timer 4 is used to generate PWM outputs for the gates and trigger the commutation tick counter and check if the motor is spinning on overflow. The overflow event interrupt for Timer 4 is set outside this function at the end of the main initialization function.

Timer 0 is used by the Ardiono core to generate interrupts. For reference, it is set up in mode 3 (Fast PWM, TOP=0xFF) with a prescaler of 64. This means ovwerflow occurs ~977 times per second. The overflow interrupt is used to trigger the ADC conversion unless changed by the user.

See also
EMULATE_HALL, TIM3_FREQ, TimersSetModeBlockCommutation()

Definition at line 455 of file main.ino.

456{
457 // Set Timer1 accordingly.
458 TCCR1A = (1 << WGM11) | (0 << WGM10);
459 TCCR1B = (0 << WGM13) | (1 << WGM12);
460 TIMSK1 = (1 << TOIE1);
461
462 // Start Timer1.
463 TCCR1B |= TIM1_CLOCK_DIV_64;
464
465#if (EMULATE_HALL == TRUE)
466 // Set Timer3 accordingly.
467 TCCR3A = (1 << WGM31) | (1 << WGM30);
468 TCCR3B = (1 << WGM33) | (1 << WGM32);
469 TIMSK3 = (1 << TOIE3);
470
471 // Set top value of Timer/counter3.
472 OCR3AH = (uint8_t)(TIM3_TOP >> 8);
473 OCR3AL = (uint8_t)(0xff & TIM3_TOP);
474
475 // Start Timer3.
476 TCCR3B |= TIM1_CLOCK_DIV_8;
477#endif
478 // Set Timer4 in "PWM6 / Dual-slope" mode. Does not enable outputs yet.
479 TCCR4A = (0 << COM4A1) | (1 << COM4A0) | (0 << COM4B1) | (1 << COM4B0) | (1 << PWM4A) | (1 << PWM4B);
481 TCCR4C |= (0 << COM4D1) | (1 << COM4D0) | (1 << PWM4D);
482 TCCR4E = (1 << ENHC4);
483
484 // Set top value of Timer/counter4.
485 TC4H = (uint8_t)(motorConfigs.tim4Top >> 8);
486 OCR4C = (uint8_t)(0xff & motorConfigs.tim4Top);
487
488 // Set the dead time.
489 DT4 = (DEAD_TIME_HALF(motorConfigs.tim4DeadTime) << 4) | DEAD_TIME_HALF(motorConfigs.tim4DeadTime);
490
491 // Start Timer4.
493}
#define DEAD_TIME_HALF(deadTime)
This value specifies half the dead time in number of clock cycles. Divide by frequency to get duratio...
Definition config.h:1323
#define DT_PRESCALER_DIV_PATTERN(dtPrescaler)
Deadtime generator pre-scaler selection bits based on pre-scaler value.
Definition config.h:1313
#define TIM3_TOP
Calculated top value for Timer 3.
Definition config.h:1331
#define TIM4_PRESCALER_DIV_PATTERN(tim4Prescaler)
Timer 4 clock select bits based on pre-scaler value.
Definition config.h:1295
#define CHOOSE_DT_PRESCALER(deadTime)
Macro to choose Timer4 dead time pre-scaler based on the dead time.
Definition config.h:912
#define CHOOSE_TIM4_PRESCALER(tim4Freq)
Macro to choose Timer4 pre-scaler.
Definition config.h:894
#define TIM1_CLOCK_DIV_64
Timer1 clock - i/o clk with division factor 64.
Definition config.h:1022
#define TIM1_CLOCK_DIV_8
Timer1 clock - i/o clk with division factor 8.
Definition config.h:1020
Here is the caller graph for this function:

Variable Documentation

◆ commutationTicks

volatile uint16_t commutationTicks = 0

The number of 'ticks' between two hall sensor changes (counter).

This variable is used to count the number of 'ticks' between each hall sensor change. It is cleared when the hall sensor change occurs. One 'tick' is one PWM period.

Note
The speed of the motor is inversely proportional to this value, but this variable is also reset to 0 when a hall sensor change is detected, so cannot be used to infer speed of the motor.
See also
lastCommutationTicks

Definition at line 81 of file main.ino.

◆ else

else
Initial value:
{
const uint8_t blockCommutationTableReverse[32]
Block Commutation Port Direction Masks for Reverse Driving.
Definition tables.h:128

Definition at line 891 of file main.ino.

◆ hall

uint8_t hall
Initial value:
{
const uint8_t *tableAddress

Definition at line 883 of file main.ino.

◆ ibus

volatile uint16_t ibus = 0

Hi-side Current (IBUS) measurement (Register Value).

The most recent current measurement is stored in this variable.

The range is 0-1023.

This value is not scaled and represents the raw ADC register value. To obtain the scaled current value in amperes, you can use the formula:

\[ \text{Current (A)} = \frac{\text{REGISTER_VALUE} \times 0.004888 \times 1000000}{\text{IBUS_GAIN} \times \text{IBUS_SENSE_RESISTOR}} \]

Where:

  • REGISTER_VALUE : The raw ADC register value stored in this variable.
  • 0.004888 : The conversion factor for a 10-bit ADC with a Vref of 5V.
  • IBUS_GAIN : The gain of the current sense operational amplifier.
  • IBUS_SENSE_RESISTOR : The value of the shunt resistor in micro-ohms (μΩ).

The NEVB-MTR1-I56-1 comes with a current op-amp with a gain factor of 50 and a current sense resistor of value 4 mΩ. This corresponds to approximately 0.0244 amperes (A) per register value.

See also
IBUS_WARNING_THRESHOLD, IBUS_ERROR_THRESHOLD

Definition at line 137 of file main.ino.

◆ iphaseU

volatile int16_t iphaseU = 0

In-line Phase U current current measurement (Register Value).

The most recent current measurement is stored in this variable.

The range is 0-1023.

This value is not scaled and represents the raw ADC register value. To obtain the scaled current value in amperes, you can use the formula:

\[ \text{Current (A)} = \frac{\text{REGISTER_VALUE} \times 0.004888 \times 1000000}{\text{IBUS_GAIN} \times \text{IBUS_SENSE_RESISTOR}} \]

Where:

  • REGISTER_VALUE : The raw ADC register value stored in this variable.
  • 0.004888 : The conversion factor for a 10-bit ADC with a Vref of 5V.
  • IPHASE_GAIN : The gain of the current sense operational amplifier.
  • IPHASE_SENSE_RESISTOR : The value of the shunt resistor in micro-ohms (μΩ).

The NEVB-MTR1-I56-1 comes with a current op-amp with a gain factor of 20 and a current sense resistor of value 2.5 mΩ. This corresponds to approximately TODO: amperes (A) per register value.

Note
It is not used for any significant purpose in this implementation, but the measurement is updated.

Definition at line 167 of file main.ino.

◆ iphaseV

volatile int16_t iphaseV = 0

In-line Phase V current current measurement (Register Value).

The most recent current measurement is stored in this variable.

The range is 0-1023.

This value is not scaled and represents the raw ADC register value. To obtain the scaled current value in amperes, you can use the formula:

\[ \text{Current (A)} = \frac{\text{REGISTER_VALUE} \times 0.004888 \times 1000000}{\text{IBUS_GAIN} \times \text{IBUS_SENSE_RESISTOR}} \]

Where:

  • REGISTER_VALUE : The raw ADC register value stored in this variable.
  • 0.004888 : The conversion factor for a 10-bit ADC with a Vref of 5V.
  • IPHASE_GAIN : The gain of the current sense operational amplifier.
  • IPHASE_SENSE_RESISTOR : The value of the shunt resistor in micro-ohms (μΩ).

The NEVB-MTR1-I56-1 comes with a current op-amp with a gain factor of 20 and a current sense resistor of value 2.5 mΩ. This corresponds to approximately TODO: amperes (A) per register value.

Note
It is not used for any significant purpose in this implementation, but the measurement is updated.

Definition at line 196 of file main.ino.

◆ iphaseW

volatile int16_t iphaseW = 0

In-line Phase W current current measurement (Register Value).

The most recent current measurement is stored in this variable.

The range is 0-1023.

This value is not scaled and represents the raw ADC register value. To obtain the scaled current value in amperes, you can use the formula:

\[ \text{Current (A)} = \frac{\text{REGISTER_VALUE} \times 0.004888 \times 1000000}{\text{IBUS_GAIN} \times \text{IBUS_SENSE_RESISTOR}} \]

Where:

  • REGISTER_VALUE : The raw ADC register value stored in this variable.
  • 0.004888 : The conversion factor for a 10-bit ADC with a Vref of 5V.
  • IPHASE_GAIN : The gain of the current sense operational amplifier.
  • IPHASE_SENSE_RESISTOR : The value of the shunt resistor in micro-ohms (μΩ).

The NEVB-MTR1-I56-1 comes with a current op-amp with a gain factor of 20 and a current sense resistor of value 2.5 mΩ. This corresponds to approximately TODO: amperes (A) per register value.

Note
It is not used for any significant purpose in this implementation, but the measurement is updated.

Definition at line 226 of file main.ino.

◆ lastCommutationTicks

volatile uint16_t lastCommutationTicks = 0xffff

The number of 'ticks' between two hall sensor changes (store).

This variable is used to store the number of 'ticks' between each hall sensor change. It is set to the value in commutationTicks before it is cleared when the hall sensor change occurs.

One 'tick' is one PWM period. The speed of the motor is inversely proportional to this value.

See also
commutationTicks

Definition at line 94 of file main.ino.

◆ motorConfigs

volatile motorconfigs_t motorConfigs

Motor Configs.

This variable contains some of the motor configurations.

Definition at line 66 of file main.ino.

◆ PORTB

PORTB = (uint8_t)pgm_read_byte_near(tableAddress++)

Definition at line 902 of file main.ino.

◆ PORTC

PORTC = (uint8_t)pgm_read_byte_near(tableAddress++)

Definition at line 903 of file main.ino.

◆ PORTD

PORTD = (uint8_t)pgm_read_byte_near(tableAddress++)

Definition at line 904 of file main.ino.

◆ speedInput

volatile uint8_t speedInput = 0

The most recent "speed" input measurement.

This variable is set by the ADC from the speed input reference pin. The range is 0-255.

Definition at line 101 of file main.ino.

◆ speedOutput

volatile uint8_t speedOutput = 0

The most recent "speed" output from the speed controller.

This variable controls the duty cycle of the generated PWM signals. The range is 0-255.

Definition at line 108 of file main.ino.

◆ tableAddress

tableAddress = (hall * 4)

Definition at line 895 of file main.ino.

◆ TCCR4E

TCCR4E = (uint8_t)pgm_read_byte_near(tableAddress)

Definition at line 905 of file main.ino.

◆ vbusVref

volatile uint16_t vbusVref = 0

VBUS voltage measurement (Register Value)

The most recent VBUS voltage measurement is stored in this variable.

The range is 0-1023.

This value is not scaled and represents the raw ADC register value. To obtain the scaled VBUS voltage in volts, you can use the formula:

\[ \text{Voltage (V)} = \frac{\text{REGISTER_VALUE} \times 0.004888 \times (\text{VBUS_RTOP} + \text{VBUS_RBOTTOM})}{\text{VBUS_RBOTTOM}} \]

Where:

  • REGISTER_VALUE : The raw ADC register value stored in this variable.
  • 0.004888 : The conversion factor for a 10-bit ADC with a Vref of 5V.
  • VBUS_RTOP : The top resistor value in ohms (Ω) in the potential divider.
  • VBUS_RBOTTOM : The bottom resistor value in ohms (Ω) in the potential divider.

The NEVB-MTR1-C-1 has a resistor divider with RTOP of 100 kΩ and RBOTTOM of 6.2 kΩ, so it corresponds to approximately 0.0837 volts (V) per register value.

Note
It is not used for any significant purpose in this implementation, but the measurement is updated.

Definition at line 255 of file main.ino.