Skip to content

Commit 066cd03

Browse files
committed
added TLE5012B driver
1 parent d74656b commit 066cd03

File tree

6 files changed

+337
-0
lines changed

6 files changed

+337
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ What's here? See the sections below. Each driver or function should come with it
2121
- [MA730 SPI driver](src/encoders/ma730/) - SPI driver for the MPS MagAlpha MA730 absolute position magnetic rotary encoder IC.
2222
- [MA730 SSI driver](src/encoders/ma730/) - SSI driver for the MPS MagAlpha MA730 absolute position magnetic rotary encoder IC.
2323
- [AS5145 SSI driver](src/encoders/as5145/) - SSI driver for the AMS AS5145 and AS5045 absolute position magnetic rotary encoder ICs.
24+
- [TLE5012B SPI driver](src/encoders/tle5012b/) - SPI (half duplex) driver for TLE5012B absolute position magnetic rotary encoder IC.
2425
- [STM32 Hardware Encoder](src/encoders/stm32hwencoder/) - Hardware timer based encoder driver for ABI type quadrature encoders.
2526

2627
### Communications
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
#include "./MagneticSensorTLE5012B.h"
3+
4+
#if defined(_STM32_DEF_)
5+
6+
MagneticSensorTLE5012B::MagneticSensorTLE5012B(int data, int sck, int nCS) : TLE5012B(data, sck, nCS) { };
7+
MagneticSensorTLE5012B::~MagneticSensorTLE5012B(){ };
8+
9+
void MagneticSensorTLE5012B::init() {
10+
this->TLE5012B::init();
11+
this->Sensor::init();
12+
};
13+
14+
float MagneticSensorTLE5012B::getSensorAngle() {
15+
return getCurrentAngle();
16+
};
17+
18+
#endif
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
#ifndef __MAGNETIC_SENSOR_TLE5012B_H__
3+
#define __MAGNETIC_SENSOR_TLE5012B_H__
4+
5+
#include "./STM32TLE5012B.h"
6+
7+
#if defined(_STM32_DEF_)
8+
9+
#include "common/base_classes/Sensor.h"
10+
11+
12+
13+
14+
class MagneticSensorTLE5012B : public Sensor, public TLE5012B {
15+
public:
16+
MagneticSensorTLE5012B(int data, int sck, int nCS);
17+
~MagneticSensorTLE5012B();
18+
virtual void init() override;
19+
virtual float getSensorAngle() override;
20+
};
21+
22+
23+
24+
#endif
25+
#endif

src/encoders/tle5012b/README.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# SimpleFOC Driver for TLE5012B encoder for STM32 MCUs
2+
3+
This driver code is compatible with STM32 MCUs. Based loosely on code from [here](https://github.com/xerootg/btt-s42b-simplefoc), with many thanks to @xerootg
4+
5+
## Hardware setup
6+
7+
Connect the data pin of the sensor to the MOSI (COPI) line of the MCU. The SCLK and nCS lines are connected as normal.
8+
9+
## Software setup
10+
11+
Sample code:
12+
13+
```
14+
#include <Arduino.h>
15+
#include <SimpleFOC.h>
16+
#include <SimpleFOCDrivers.h>
17+
#include "encoders/tle5012b/MagneticSensorTLE5012B.h"
18+
19+
MagneticSensorTLE5012B sensor(PB15,PB13,PB12);
20+
21+
long ts;
22+
23+
void setup() {
24+
Serial.begin(115200);
25+
while (!Serial) ;
26+
delay(2000);
27+
28+
Serial.println("Initializing sensor...");
29+
30+
sensor.init();
31+
32+
Serial.println("Sensor initialized.");
33+
34+
ts = millis();
35+
}
36+
37+
void loop() {
38+
sensor.update();
39+
if (millis() - ts > 1000) {
40+
Serial.println(sensor.getAngle(), 3);
41+
ts = millis();
42+
}
43+
delay(1);
44+
}
45+
```
46+
47+
## Other MCUs
48+
49+
Infineon provides a driver library compatible with Atmel AVR (Arduino UNO, Nano, etc...) and Infineon XMC MCUs. If you have one of those MCUs, you can use this library in conjunction with the GenericSensor class in SimpleFOC.
50+
51+
```
52+
#include <SimpleFOC.h>
53+
#include <TLE5012-ino.hpp>
54+
55+
Tle5012Ino Tle5012Sensor = Tle5012Ino();
56+
errorTypes checkError = NO_ERROR;
57+
58+
float readMySensor(){
59+
// read my sensor
60+
// return the angle value in radians in between 0 and 2PI
61+
62+
Tle5012Sensor.getAngleValue(d);
63+
d = (d + 180);
64+
if ( d + 40.9 > 360 ) {
65+
d = (d + 40.9) - 360;
66+
}
67+
else
68+
d = d + 40.9;
69+
70+
d = d * 0.0174533;
71+
return d;
72+
}
73+
void initMySensor(){
74+
// do the init
75+
checkError = Tle5012Sensor.begin();
76+
}
77+
78+
// empty constructor
79+
GenericSensor sensor = GenericSensor(readMySensor, initMySensor);
80+
81+
void setup(){
82+
...
83+
//init sensor and use it further with foc...
84+
sensor.init();
85+
...
86+
}
87+
```
88+
89+
Other MCUs are currently not supported. The problem is that the sensor uses SPI in half-duplex mode, which is not supported by Arduino framework. So for each MCU type a custom driver has to be written to get the half-duplex SPI communication to work. There are currently no plans to support other MCUs on our side, but we will gladly accept pull requests :-)
90+
91+
If you can find other libraries for other MCUs, you can use the GenericSensor approach to integrate them.
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
2+
#include "STM32TLE5012B.h"
3+
4+
#if defined(_STM32_DEF_)
5+
6+
7+
#include "utility/spi_com.h"
8+
extern "C" uint32_t spi_getClkFreqInst(SPI_TypeDef *spi_inst);
9+
10+
11+
12+
TLE5012B::TLE5012B(int data, int sck, int nCS, uint32_t freq) {
13+
_data = data;
14+
_sck = sck;
15+
_nCS = nCS;
16+
_freq = freq;
17+
};
18+
19+
TLE5012B::~TLE5012B() {
20+
21+
};
22+
23+
24+
void TLE5012B::init() {
25+
pinMode(_nCS, OUTPUT);
26+
digitalWrite(_nCS, HIGH);
27+
28+
// initialize pins
29+
GPIO_InitTypeDef gpio;
30+
gpio.Pin = digitalPinToBitMask(_data);
31+
gpio.Mode = GPIO_MODE_AF_PP;
32+
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
33+
HAL_GPIO_Init(digitalPinToPort(_data), &gpio);
34+
gpio.Pin = digitalPinToBitMask(_sck);
35+
gpio.Mode = GPIO_MODE_AF_PP;
36+
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
37+
HAL_GPIO_Init(digitalPinToPort(_sck), &gpio);
38+
39+
SPI_TypeDef *spi_data = (SPI_TypeDef*)pinmap_peripheral(digitalPinToPinName(_data), PinMap_SPI_MOSI);
40+
SPI_TypeDef *spi_sclk = (SPI_TypeDef*)pinmap_peripheral(digitalPinToPinName(_sck), PinMap_SPI_SCLK);
41+
SPI_TypeDef *spi_inst = (SPI_TypeDef*)pinmap_merge_peripheral(spi_data, spi_sclk);
42+
43+
pinmap_pinout(digitalPinToPinName(_data), PinMap_SPI_MOSI);
44+
pinmap_pinout(digitalPinToPinName(_sck), PinMap_SPI_SCLK);
45+
46+
#if defined SPI1_BASE
47+
if (spi_inst == SPI1) {
48+
__HAL_RCC_SPI1_CLK_ENABLE();
49+
__HAL_RCC_SPI1_FORCE_RESET();
50+
__HAL_RCC_SPI1_RELEASE_RESET();
51+
}
52+
#endif
53+
54+
#if defined SPI2_BASE
55+
if (spi_inst == SPI2) {
56+
__HAL_RCC_SPI2_CLK_ENABLE();
57+
__HAL_RCC_SPI2_FORCE_RESET();
58+
__HAL_RCC_SPI2_RELEASE_RESET();
59+
}
60+
#endif
61+
62+
#if defined SPI3_BASE
63+
if (spi_inst == SPI3) {
64+
__HAL_RCC_SPI3_CLK_ENABLE();
65+
__HAL_RCC_SPI3_FORCE_RESET();
66+
__HAL_RCC_SPI3_RELEASE_RESET();
67+
}
68+
#endif
69+
70+
#if defined SPI4_BASE
71+
if (spi_inst == SPI4) {
72+
__HAL_RCC_SPI4_CLK_ENABLE();
73+
__HAL_RCC_SPI4_FORCE_RESET();
74+
__HAL_RCC_SPI4_RELEASE_RESET();
75+
}
76+
#endif
77+
78+
#if defined SPI5_BASE
79+
if (spi_inst == SPI5) {
80+
__HAL_RCC_SPI5_CLK_ENABLE();
81+
__HAL_RCC_SPI5_FORCE_RESET();
82+
__HAL_RCC_SPI5_RELEASE_RESET();
83+
}
84+
#endif
85+
86+
#if defined SPI6_BASE
87+
if (spi_inst == SPI6) {
88+
__HAL_RCC_SPI6_CLK_ENABLE();
89+
__HAL_RCC_SPI6_FORCE_RESET();
90+
__HAL_RCC_SPI6_RELEASE_RESET();
91+
}
92+
#endif
93+
94+
_spi.Instance = spi_inst;
95+
_spi.Init.Direction = SPI_DIRECTION_1LINE;
96+
_spi.Init.Mode = SPI_MODE_MASTER;
97+
_spi.Init.DataSize = SPI_DATASIZE_8BIT;
98+
_spi.Init.CLKPolarity = SPI_POLARITY_LOW;
99+
_spi.Init.CLKPhase = SPI_PHASE_2EDGE;
100+
_spi.Init.NSS = SPI_NSS_SOFT;
101+
_spi.Init.FirstBit = SPI_FIRSTBIT_MSB;
102+
_spi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
103+
_spi.Init.CRCPolynomial = 7;
104+
_spi.Init.TIMode = SPI_TIMODE_DISABLE;
105+
_spi.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
106+
107+
uint32_t spi_freq = spi_getClkFreqInst(spi_inst);
108+
if (_freq >= (spi_freq / SPI_SPEED_CLOCK_DIV2_MHZ)) {
109+
_spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
110+
} else if (_freq >= (spi_freq / SPI_SPEED_CLOCK_DIV4_MHZ)) {
111+
_spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
112+
} else if (_freq >= (spi_freq / SPI_SPEED_CLOCK_DIV8_MHZ)) {
113+
_spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
114+
} else if (_freq >= (spi_freq / SPI_SPEED_CLOCK_DIV16_MHZ)) {
115+
_spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
116+
} else if (_freq >= (spi_freq / SPI_SPEED_CLOCK_DIV32_MHZ)) {
117+
_spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
118+
} else if (_freq >= (spi_freq / SPI_SPEED_CLOCK_DIV64_MHZ)) {
119+
_spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
120+
} else if (_freq >= (spi_freq / SPI_SPEED_CLOCK_DIV128_MHZ)) {
121+
_spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
122+
} else {
123+
_spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
124+
}
125+
126+
if (HAL_SPI_Init(&_spi) != HAL_OK) {
127+
// setup error
128+
Serial.println("TLE5012B setup error");
129+
}
130+
};
131+
132+
uint16_t TLE5012B::readRawAngle() {
133+
uint8_t data[4];
134+
readBytes(TLE5012B_ANGLE_REG, data, 2);
135+
return (((uint16_t)data[0] << 8) | data[1]) & 0x7FFF;
136+
};
137+
138+
139+
float TLE5012B::getCurrentAngle() {
140+
return ((float)readRawAngle())/TLE5012B_CPR * _2PI;
141+
}; // angle in radians, return current value
142+
143+
144+
void TLE5012B::readBytes(uint16_t reg, uint8_t *data, uint8_t len) {
145+
digitalWrite(_nCS, LOW);
146+
147+
reg |= TLE5012B_READ_REGISTER + (len>>1);
148+
uint8_t txbuffer[2] = { (uint8_t)(reg >> 8), (uint8_t)(reg & 0x00FF) };
149+
HAL_SPI_Transmit(&_spi, txbuffer, 2, 100); // TODO check return value for error, timeout
150+
//delayMicroseconds(1);
151+
HAL_SPI_Receive(&_spi, data, len + 2, 100);
152+
153+
digitalWrite(_nCS, HIGH);
154+
};
155+
156+
157+
#endif
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#ifndef __TLE5012B_H__
2+
#define __TLE5012B_H__
3+
4+
#include "Arduino.h"
5+
6+
#if defined(_STM32_DEF_)
7+
8+
9+
#define _2PI 6.28318530718f
10+
#define TLE5012B_CPR 32768.0f
11+
12+
#define TLE5012B_READ_REGISTER 0x8000
13+
14+
enum TLE5012B_Register : uint16_t {
15+
TLE5012B_ANGLE_REG = 0x0020,
16+
TLE5012B_SPEED_REG = 0x0030
17+
};
18+
19+
20+
21+
class TLE5012B {
22+
public:
23+
TLE5012B(int data, int sck, int nCS, uint32_t freq = 1000000);
24+
~TLE5012B();
25+
virtual void init();
26+
27+
uint16_t readRawAngle();
28+
float getCurrentAngle(); // angle in radians, return current value
29+
private:
30+
31+
void readBytes(uint16_t reg, uint8_t *data, uint8_t len);
32+
33+
int _data;
34+
int _sck;
35+
int _nCS;
36+
uint32_t _freq;
37+
SPI_HandleTypeDef _spi;
38+
};
39+
40+
41+
42+
43+
#endif
44+
45+
#endif

0 commit comments

Comments
 (0)