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
68 changes: 68 additions & 0 deletions .github/workflows/ccpp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: Library Compile
on: push
jobs:
build:
name: Test compile
runs-on: ubuntu-latest
strategy:
matrix:
arduino-boards-fqbn:
- arduino:avr:uno # arudino uno
- arduino:sam:arduino_due_x # arduino due
- arduino:samd:nano_33_iot # samd21
- adafruit:samd:adafruit_metro_m4 # samd51
- esp32:esp32:esp32 # esp32
- esp32:esp32:esp32s2 # esp32s2
- STM32:stm32:GenF1:pnum=BLUEPILL_F103C8 # stm32 bluepill
- STM32:stm32:Nucleo_64:pnum=NUCLEO_F411RE # stm32 nucleo
- arduino:mbed_rp2040:pico # rpi pico
include:
- arduino-boards-fqbn: arduino:avr:uno
sketch-names: '**.ino'
required-libraries: Simple FOC
- arduino-boards-fqbn: arduino:sam:arduino_due_x
required-libraries: Simple FOC
sketch-names: '**.ino'
- arduino-boards-fqbn: arduino:samd:nano_33_iot
required-libraries: Simple FOC
sketch-names: '**.ino'
- arduino-boards-fqbn: arduino:mbed_rp2040:pico
required-libraries: Simple FOC
sketch-names: '**.ino'
- arduino-boards-fqbn: adafruit:samd:adafruit_metro_m4
platform-url: https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
required-libraries: Simple FOC
sketch-names: '**.ino'
# - arduino-boards-fqbn: esp32:esp32:esp32doit-devkit-v1
# platform-url: https://dl.espressif.com/dl/package_esp32_index.json
# required-libraries: Simple FOC
# sketch-names: '**.ino'
- arduino-boards-fqbn: esp32:esp32:esp32 # esp32
platform-url: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json
required-libraries: Simple FOC
sketch-names: '**.ino'
- arduino-boards-fqbn: esp32:esp32:esp32s2 # esp32s2
platform-url: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json
required-libraries: Simple FOC
sketch-names: '**.ino'
- arduino-boards-fqbn: STM32:stm32:GenF1:pnum=BLUEPILL_F103C8
platform-url: https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json
required-libraries: Simple FOC
sketch-names: '**.ino'
- arduino-boards-fqbn: STM32:stm32:Nucleo_64:pnum=NUCLEO_F411RE
platform-url: https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json
required-libraries: Simple FOC
sketch-names: '**.ino'
# Do not cancel all jobs / architectures if one job fails
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@master
- name: Compile all examples
uses: ArminJo/arduino-test-compile@master
with:
arduino-board-fqbn: ${{ matrix.arduino-boards-fqbn }}
required-libraries: ${{ matrix.required-libraries }}
platform-url: ${{ matrix.platform-url }}
sketch-names: ${{ matrix.sketch-names }}
sketches-exclude: ${{ matrix.sketches-exclude }}
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# SimpleFOC Driver and Support Library

![Library Compile](https://github.com/simplefoc/Arduino-FOC-drivers/workflows/Library%20Compile/badge.svg)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)


This library contains an assortment of drivers and supporting code for SimpleFOC.

The intent is to keep the core of SimpleFOC clean, and thus easy to maintain, understand and port to different platforms. In addition to this core, there are various drivers and supporting code which has grown around SimpleFOC, and which we would like to make available to the community.
Expand All @@ -17,6 +21,9 @@ What's here? See the sections below. Each driver or function should come with it
- [AS5048A SPI driver](src/encoders/as5048a/) - SPI driver for the AMS AS5048A absolute position magnetic rotary encoder IC.
- [AS5047 SPI driver](src/encoders/as5047/) - SPI driver for the AMS AS5047P and AS5047D absolute position magnetic rotary encoder ICs.
- [MA730 SPI driver](src/encoders/ma730/) - SPI driver for the MPS MagAlpha MA730 absolute position magnetic rotary encoder IC.
- [MA730 SSI driver](src/encoders/ma730/) - SSI driver for the MPS MagAlpha MA730 absolute position magnetic rotary encoder IC.
- [AS5145 SSI driver](src/encoders/as5145/) - SSI driver for the AMS AS5145 and AS5045 absolute position magnetic rotary encoder ICs.
- [TLE5012B SPI driver](src/encoders/tle5012b/) - SPI (half duplex) driver for TLE5012B absolute position magnetic rotary encoder IC.
- [STM32 Hardware Encoder](src/encoders/stm32hwencoder/) - Hardware timer based encoder driver for ABI type quadrature encoders.

### Communications
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
#include "Arduino.h"
#include <Wire.h>
#include <SimpleFOC.h>
#include <Math.h>
#include <SimpleFOCDrivers.h>
#include "drivers/drv8316/drv8316.h"




BLDCMotor motor = BLDCMotor(11);
DRV8316Driver3PWM driver = DRV8316Driver3PWM(A3,A4,2,7,false); // MKR1010 3-PWM
DRV8316Driver3PWM driver = DRV8316Driver3PWM(2,3,4,7,false); // use the right pins for your setup!
#define ENABLE_A 0
#define ENABLE_B 1
#define ENABLE_C 6
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
#include "Arduino.h"
#include <Wire.h>
#include <SimpleFOC.h>
#include <Math.h>
#include <SimpleFOCDrivers.h>
#include "drivers/drv8316/drv8316.h"




BLDCMotor motor = BLDCMotor(11);
DRV8316Driver6PWM driver = DRV8316Driver6PWM(A3,0,A4,1,2,6,7,false); // MKR1010 6-PWM
DRV8316Driver6PWM driver = DRV8316Driver6PWM(0,1,2,3,4,6,7,false); // use the right pins for your setup!



Expand Down
9 changes: 8 additions & 1 deletion keywords.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
SimpleFOC KEYWORD1
DRV8316 KEYWORD1
DRV8316 KEYWORD1
AS5048A KEYWORD1
AS5047 KEYWORD1
AS5145 KEYWORD1
MA730 KEYWORD1
TLE5012B KEYWORD1
I2CCommander KEYWORD1

2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ paragraph=SimpleFOC runs BLDC and Stepper motors using the FOC algorithm. This l
category=Device Control
url=https://docs.simplefoc.com
architectures=*
includes=DRV8316.h
includes=SimpleFOCDrivers.h
depends=Simple FOC
53 changes: 32 additions & 21 deletions src/comms/i2c/I2CCommander.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,6 @@ void I2CCommander::addMotor(FOCMotor* motor){



I2CCommander_Motor_Status I2CCommander::getMotorStatus(uint8_t motorNum){
if (motorNum<numMotors){
if (motors[motorNum]->zero_electric_angle==NOT_SET) // TODO detect open-loop uninitialized state!
return I2CCommander_Motor_Status::MOT_UNINITIALIZED;
if (motors[motorNum]->enabled==0)
return I2CCommander_Motor_Status::MOT_DISABLED;
if (motors[motorNum]->shaft_velocity >= I2CCOMMANDER_MIN_VELOCITY_FOR_MOTOR_MOVING)
return I2CCommander_Motor_Status::MOT_MOVING;
return I2CCommander_Motor_Status::MOT_IDLE;
}
return I2CCommander_Motor_Status::MOT_UNKNOWN;
};




bool I2CCommander::readBytes(void* valueToSet, uint8_t numBytes){
if (_wire->available()>=numBytes){
Expand Down Expand Up @@ -85,10 +70,19 @@ void I2CCommander::onRequest(){



/*
Reads values from I2C bus and updates the motor's values.

Currently this isn't really thread-safe, but works ok in practice on 32-bit MCUs.

Do not use on 8-bit architectures where the 32 bit writes may not be atomic!

Plan to make this safe: the writes should be buffered, and not actually executed
until in the main loop by calling commander->run();
the run() method disables interrupts while the updates happen.
*/
bool I2CCommander::receiveRegister(uint8_t motorNum, uint8_t registerNum, int numBytes) {
int val;
float floatval;
switch (registerNum) {
case REG_MOTOR_ADDRESS:
val = _wire->read(); // reading one more byte is definately ok, since numBytes>1
Expand Down Expand Up @@ -230,7 +224,23 @@ bool I2CCommander::receiveRegister(uint8_t motorNum, uint8_t registerNum, int nu



/*
Reads values from motor/sensor and writes them to I2C bus. Intended to be run
from the Wire.onRequest interrupt.

Assumes atomic 32 bit reads. On 8-bit arduino this assumption does not hold and this
code is not safe on those platforms. You might read "half-written" floats.

A solution might be to maintain a complete set of shadow registers in the commander
class, and update them in the run() method (which runs with interrupts off). Not sure
of the performance impact of all those 32 bit read/writes though. In any case, since
I use only 32 bit MCUs I'll leave it as an excercise to the one who needs it. ;-)

On 32 bit platforms the implication is that reads will occur atomically, so data will
be intact, but they can occur at any time during motor updates, so different values might
not be in a fully consistent state (i.e. phase A current might be from the current iteration
but phase B current from the previous iteration).
*/
bool I2CCommander::sendRegister(uint8_t motorNum, uint8_t registerNum) {
// read the current register
switch(registerNum) {
Expand All @@ -239,8 +249,7 @@ bool I2CCommander::sendRegister(uint8_t motorNum, uint8_t registerNum) {
_wire->write((uint8_t)lastcommandregister);
_wire->write((uint8_t)lastcommanderror+1);
for (int i=0;(i<numMotors && i<28); i++) { // at most 28 motors, so we can fit in one packet
uint8_t status = (uint8_t)getMotorStatus(i);
_wire->write(status);
_wire->write(motors[motorNum]->motor_status);
}
break;
case REG_MOTOR_ADDRESS:
Expand Down Expand Up @@ -377,7 +386,8 @@ bool I2CCommander::sendRegister(uint8_t motorNum, uint8_t registerNum) {
writeFloat(motors[motorNum]->current_limit);
break;
case REG_MOTION_DOWNSAMPLE:
_wire->write((uint32_t)motors[motorNum]->motion_downsample);
_wire->write((int)motors[motorNum]->motion_downsample); // TODO int will have different sizes on different platforms
// but using uint32 doesn't compile clean on all, e.g. RP2040
break;

case REG_ZERO_ELECTRIC_ANGLE:
Expand All @@ -393,11 +403,12 @@ bool I2CCommander::sendRegister(uint8_t motorNum, uint8_t registerNum) {
writeFloat(motors[motorNum]->phase_resistance);
break;
case REG_POLE_PAIRS:
_wire->write((uint32_t)motors[motorNum]->pole_pairs);
_wire->write((int)motors[motorNum]->pole_pairs);
break;

case REG_SYS_TIME:
_wire->write(millis());
// TODO how big is millis()? Same on all platforms?
_wire->write((int)millis());
break;
case REG_NUM_MOTORS:
_wire->write(numMotors);
Expand Down
2 changes: 0 additions & 2 deletions src/comms/i2c/I2CCommander.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ class I2CCommander {
void onReceive(int numBytes);
void onRequest();

I2CCommander_Motor_Status getMotorStatus(uint8_t motorNum);

protected:
void writeFloat(float value);
bool readBytes(void* valueToSet, uint8_t numBytes);
Expand Down
18 changes: 0 additions & 18 deletions src/comms/i2c/I2CCommanderRegisters.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

#ifndef __I2CCOMMANDERREGISTERS_H__
#define __I2CCOMMANDERREGISTERS_H__

Expand Down Expand Up @@ -62,23 +61,6 @@ typedef enum : uint8_t {



// TODO stati are work in progress. For example, it would be good to differentiate between not moving because stalled,
// and not moving because target set-point has been reached. It would be good to be able to track initialization state
// and error state.
typedef enum : uint8_t {
MOT_UNINITIALIZED = 0x00, // Motor is not initialized
MOT_INITIALIZING = 0x01, // TODO - this status is not used at the moment, can't detect it

MOT_DISABLED = 0x02, // motor is disabled
MOT_IDLE = 0x03, // motor is enabled, but not moving (current_velocity==target==0 in velocity mode,
// or position==target in position mode)
MOT_MOVING = 0x04, // motor is moving

MOT_ERROR = 0x05, // TODO - motor is disabled because an error has occurred
MOT_INIT_FAILED = 0x0F, // motor initialization failed
MOT_UNKNOWN = 0xFF // incorrect motor number
} I2CCommander_Motor_Status;



#endif
4 changes: 4 additions & 0 deletions src/comms/i2c/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ This code takes the point of view that the motor driver (the "muscle") is the I2

This is new code, and has not been extensively tested. Your milage may vary. That said, basic use cases have been tested, and we would certainly appreciate feedback and help with testing it out.

In particular, there are concurrency issues with reading/writing the SimpleFOC motor values from I2C while the motor is running. These should be solved soon in an upcoming version.

**Do not run on 8-bit MCUs!** The code currently assumes atomic 32 bit reads, so running on Arduino UNO or Nano is unfortunately a no-go.

## Using

As would be expected for I2C, each target device needs a unique I2C address on its bus, and setting up and discovering these addresses is out-of-scope for I2CCommander. Setting up and configuring the TwoWire objects (which pins, speed, etc...) is also out of scope and finished, initialized TwoWire objects must be passed to I2CCommander. If you don't specify a different reference, the standard *Wire* object is assumed.
Expand Down
4 changes: 2 additions & 2 deletions src/drivers/drv8316/drv8316.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ enum DRV8316_PWMMode {


enum DRV8316_SDOMode {
OpenDrain = 0b0,
PushPull = 0b1
SDOMode_OpenDrain = 0b0,
SDOMode_PushPull = 0b1
};


Expand Down
Loading