Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 24 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,14 @@ The intent is to keep the core of SimpleFOC clean, and thus easy to maintain, un

## New Release

v1.0.3 - Released March 2023, for Simple FOC 2.3.0

What's changed since 1.0.2?
- New Sensor: MT6835
- Fixed bugs

What's changed since 1.0.1?
- Calibrated sensor by @MarethyuPrefect
- New Sensors: MT6701, MA330, MT6816
- Fixed bugs
v1.0.4 - Released June 2023, for Simple FOC 2.3.0

What's changed since 1.0.3?
- New Comms/Input: STM32SpeedDirCommander
- New Utility: STM32PWMInput
- Fixed MT6835 driver bugs
- Improved AS5047 driver, fixed bugs
- Improved AS5047U driver, fixed bugs

## What is included

Expand All @@ -45,10 +42,16 @@ What is here? See the sections below. Each driver or function should come with i
- [MT6816 SPI driver](src/encoders/mt6816/) - SPI driver for the MagnTek MT6816 absolute position magnetic rotary encoder IC.
- [MT6701 SSI driver](src/encoders/mt6701/) - SSI driver for the MagnTek MT6701 absolute position magnetic rotary encoder IC.
- [MT6835 SPI driver](src/encoders/mt6835/) - SPI driver for the MagnTek MT6835 21 bit magnetic rotary encoder IC.
- [STM32 PWM sensor driver](src/encoders/stm32pwmsensor/) - STM32 native timer-based driver for PWM angle sensors.

### Communications

- [I2CCommander I2C driver](src/comms/i2c/) - I2C communications protocol and drivers for both controller and target devices.
- [STM32 SpeedDir Input](src/comms/stm32speeddir/) - Control target velocity with PWM speed and direction inputs

### Utilities

- [STM32 PWM Input driver](src/utilities/stm32pwm/) - PWM Input driver for STM32 MCUs. Accurately measure PWM inputs with zero MCU overhead.


## How to use
Expand All @@ -74,3 +77,14 @@ If you do so, please be sure to adhere to and include the [LICENSE](https://gith
## Further Documentation

Find out more information about the Arduino SimpleFOC project on the [docs website](https://docs.simplefoc.com/)

## Release History

What's changed since 1.0.2?
- New Sensor: MT6835
- Fixed bugs

What's changed since 1.0.1?
- Calibrated sensor by @MarethyuPrefect
- New Sensors: MT6701, MA330, MT6816
- Fixed bugs
4 changes: 3 additions & 1 deletion keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ AS5048A KEYWORD1
AS5047 KEYWORD1
AS5145 KEYWORD1
MA730 KEYWORD1
MT6835 KEYWORD1
SC60228 KEYWORD1
TLE5012B KEYWORD1
I2CCommander KEYWORD1

STM32HWEncoder KEYWORD1
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=SimpleFOCDrivers
version=1.0.3
version=1.0.4
author=Simplefoc <info@simplefoc.com>
maintainer=Simplefoc <info@simplefoc.com>
sentence=A library of supporting drivers for SimpleFOC. Motor drivers chips, encoder chips, current sensing and supporting code.
Expand Down
58 changes: 58 additions & 0 deletions src/comms/stm32speeddir/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@

# STM32SpeedDirInput

Control SimpleFOC using PWM speed and direction inputs.

Based on STM32 timer PWM-Input capabilities, which means this can only be used on STM32 MCUs. It can cover a wide range of PWM frequencies, and runs without MCU overhead in the timer hardware.



## Setup

The PWM speed input should be connected to either channel 1 or channel 2 of a general purpose or advanced control timer on your STM32 MCU. Suitable timers are:
- Advanced control timers: TIM1, TIM8
- General purpose timers (32 bit): TIM2, TIM5
- General purpose timers (16 bit): TIM3, TIM4, TIM9, TIM12
If in doubt, check in STM32CubeIDE and see if the PWM-Input mode can be enabled (under "Combined Channels") for the timer.

The optional direction input can be connected to any GPIO pin. By default a high level direction input is associated with a positive velocity value, while a low level direction input results in a negative velocity value. To reverse this, set the option `dir_positive_high = false`

The direction input is optional - if not provided, you can control the direction from software using the `direction` field.

The velocity values returned are in the range `min_speed` to `max_speed`, while the input PWM duty cycle should lie within the range `min_pwm` to `max_pwm`. Actual input values smaller than `min_pwm` will be treated as `min_pwm`, values larger than `max_pwm` will be treated as `max_pwm`. The behaviour for 100% or 0% duty cycles is undefined, and they should be avoided.

## Usage

Use it like this:

```c++
#include "comms/stm32speeddir/STM32SpeedDirInput.h"

// some example pins - the speed pin has to be on channel 1 or 2 of a timer
#define PIN_SPEED PC6
#define PIN_DIRECTION PB8

STM32SpeedDirInput speed_dir = STM32SpeedDirInput(PIN_SPEED, PIN_DIRECTION);

float target = 0.0f;

void setup(){
...

speed_dir.min_speed = 10.0f; // 10rad/s min speed
speed_dir.max_speed = 100.0f; // 100rad/s max speed
speed_dir.min_pwm = 5.0f; // 5% min duty cycle
speed_dir.max_pwm = 95.0f; // 95% max duty cycle
speed_dir.init();

...
}


void loop(){
target = speed_dir.getTargetVelocity();
motor.move(target);
motor.loopFOC();
}

```
29 changes: 29 additions & 0 deletions src/comms/stm32speeddir/STM32SpeedDirInput.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

#include "./STM32SpeedDirInput.h"

#if defined(_STM32_DEF_)

STM32SpeedDirInput::STM32SpeedDirInput(int pin_speed, int pin_dir) : STM32PWMInput(pin_speed) {
_pin_speed = pin_speed;
_pin_dir = pin_dir;
};

STM32SpeedDirInput::~STM32SpeedDirInput(){};

int STM32SpeedDirInput::init(){
pinMode(_pin_dir, INPUT);
return STM32PWMInput::initialize();
};


float STM32SpeedDirInput::getTargetVelocity(){
if (_pin_dir != NOT_SET)
direction = digitalRead(_pin_dir);
float speed = getDutyCyclePercent();
speed = constrain(speed, min_pwm, max_pwm);
speed = (speed - min_pwm)/(max_pwm - min_pwm) * (max_speed - min_speed) + min_speed;
return (direction == dir_positive_high) ? speed : -speed;
};


#endif
31 changes: 31 additions & 0 deletions src/comms/stm32speeddir/STM32SpeedDirInput.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

#pragma once

#include "Arduino.h"

#if defined(_STM32_DEF_)

#include "common/foc_utils.h"
#include "utilities/stm32pwm/STM32PWMInput.h"

class STM32SpeedDirInput : public STM32PWMInput {
public:
STM32SpeedDirInput(int pin_speed, int pin_dir = NOT_SET);
~STM32SpeedDirInput();

int init();
float getTargetVelocity();

float min_speed = 0; // min speed in rad/s
float max_speed = 100; // max speed in rad/s
float min_pwm = 5.0; // min duty cycle in %
float max_pwm = 95.0; // max duty cycle in %
bool dir_positive_high = true; // true if the direction pin is high when the motor is spinning in the positive direction
bool direction = true; // direction of rotation, default positive
protected:
int _pin_speed;
int _pin_dir;
};


#endif
106 changes: 100 additions & 6 deletions src/encoders/as5047/AS5047.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,21 +85,29 @@ AS5047Settings1 AS5047::readSettings1(){

void AS5047::writeSettings1(AS5047Settings1 settings){
uint16_t command = AS5047_SETTINGS1_REG; // set r=0, result is 0x0018
/*uint16_t cmdresult =*/ spi_transfer16(command);
/*cmdresult =*/ spi_transfer16(settings.reg);
spi_transfer16(command);
spi_transfer16(calcParity(settings.reg));
}


AS5047Settings2 AS5047::readSettings2(){
uint16_t command = AS5047_SETTINGS2_REG | AS5047_RW; // set r=1, result is 0x4019
/*uint16_t cmdresult =*/ spi_transfer16(command);
spi_transfer16(command);
AS5047Settings2 result = {
.reg = nop()
};
return result;
}


void AS5047::writeSettings2(AS5047Settings2 settings){
uint16_t command = AS5047_SETTINGS2_REG | AS5047_PARITY; // set r=0, result is 0x8019
spi_transfer16(command);
spi_transfer16(calcParity(settings.reg));
}



AS5047Diagnostics AS5047::readDiagnostics(){
uint16_t command = AS5047_DIAGNOSTICS_REG | AS5047_PARITY | AS5047_RW; // set r=1, result is 0xFFFC
/*uint16_t cmdresult =*/ spi_transfer16(command);
Expand All @@ -112,21 +120,96 @@ AS5047Diagnostics AS5047::readDiagnostics(){

void AS5047::enablePWM(bool enable){
AS5047Settings1 settings = readSettings1();
if (settings.pwmon == enable) return; // no change
settings.pwmon = enable;
writeSettings1(settings);
}

void AS5047::enableABI(bool enable){
AS5047Settings1 settings = readSettings1();
settings.uvw_abi = enable?0:1;
uint8_t val = enable?0:1;
if (settings.uvw_abi == val) return; // no change
settings.uvw_abi = val;
writeSettings1(settings);
}


void AS5047::enableDEAC(bool enable){
AS5047Settings1 settings = readSettings1();
uint8_t val = enable?0:1;
if (settings.daecdis == val) return; // no change
settings.daecdis = enable?0:1;
writeSettings1(settings);
}


void AS5047::useCorrectedAngle(bool useCorrected){
AS5047Settings1 settings = readSettings1();
uint8_t val = useCorrected?0:1;
if (settings.dataselect == val) return; // no change
settings.dataselect = val;
writeSettings1(settings);
}



void AS5047::setHysteresis(uint8_t hyst){
if (hyst>3) hyst = 3;
uint8_t val = 3-hyst;
AS5047Settings2 settings = readSettings2();
if (settings.hys == val) return; // no change
settings.hys = val;
writeSettings2(settings);
}




void AS5047::setABIResolution(AS5047ABIRes res){
AS5047Settings1 settings = readSettings1();
uint8_t val = (res>>3)&0x01;
if (settings.abibin!=val || settings.uvw_abi!=0) {
settings.abibin = val;
settings.uvw_abi = 0;
writeSettings1(settings);
}
AS5047Settings2 settings2 = readSettings2();
val = (res&0x07);
if (settings2.abires!=val) {
settings2.abires = val;
writeSettings2(settings2);
}
}



uint16_t AS5047::setZero(uint16_t value){
// TODO implement me!
return 0;
uint16_t command = AS5047_ZPOSL_REG | AS5047_PARITY | AS5047_RW;
spi_transfer16(command);
AS5047ZPosL posL = {
.reg = nop()
};
command = AS5047_ZPOSM_REG | AS5047_PARITY;
spi_transfer16(command);
spi_transfer16(calcParity((value>>6)&0x00FF));
command = AS5047_ZPOSL_REG;
posL.zposl = value&0x003F;
spi_transfer16(command);
spi_transfer16(calcParity(posL.reg));

return getZero();
}


uint16_t AS5047::getZero() {
uint16_t command = AS5047_ZPOSM_REG | AS5047_RW;
spi_transfer16(command);
command = AS5047_ZPOSL_REG | AS5047_PARITY | AS5047_RW;
uint16_t result = spi_transfer16(command);
AS5047ZPosL posL = {
.reg = nop()
};
return ((result&0x00FF)<<6) | posL.zposl;
}


Expand All @@ -135,6 +218,17 @@ uint16_t AS5047::nop(){
return result&AS5047_RESULT_MASK;
}


uint16_t AS5047::calcParity(uint16_t data){
data = data & 0x7FFF;
int sum = 0;
for (int i=0;i<15;i++)
if ((data>>i)&0x0001)
sum++;
return (sum&0x01)==0x01?(data|0x8000):data;
}


uint16_t AS5047::spi_transfer16(uint16_t outdata) {
if (nCS>=0)
digitalWrite(nCS, 0);
Expand Down
Loading