Merge pull request #551 from Teslafly/tle5012_enc_rebase_clean

Add Tle5012 encoder support
This commit is contained in:
Benjamin Vedder 2022-11-16 10:09:47 +01:00 committed by GitHub
commit f053aab9a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 832 additions and 39 deletions

View File

@ -73,24 +73,24 @@ endif
##############################
.PHONY: help
help:
@echo
@echo ""
@echo " This Makefile is known to work on Linux and Mac in a standard shell environment."
@echo
@echo ""
@echo " Here is a summary of the available targets:"
@echo
@echo ""
@echo " [Tool Installers]"
@echo " arm_sdk_install - Install the GNU ARM gcc toolchain"
@echo " qt_install - Install the all tools for Qt"
@echo
@echo ""
@echo " [Big Hammer]"
@echo " all_fw - Build firmware for all boards"
@echo " all_fw_package - Packaage firmware for boards in package list"
@echo
@echo ""
@echo " [Unit Tests]"
@echo " all_ut - Build all unit tests"
@echo " all_ut_xml - Run all unit tests and capture all XML output to files"
@echo " all_ut_run - Run all unit tests and dump XML output to console"
@echo
@echo ""
@echo " [Firmware]"
@echo " fw - Build firmware for default target"
@echo " supported boards are: $(ALL_BOARD_NAMES)"
@ -98,12 +98,12 @@ help:
@echo " PROJECT=<target> fw - Build firmware for <target>"
@echo " fw_<board>_clean - Remove firmware for <board>"
@echo " fw_<board>_flash - Use OpenOCD + SWD/JTAG to write firmware to <target>"
@echo
@echo ""
@echo " Hint: Add V=1 to your command line to see verbose build output."
@echo
@echo ""
@echo " Note: All tools will be installed into $(TOOLS_DIR)"
@echo " All build output will be placed in $(BUILD_DIR)"
@echo
@echo ""
$(DL_DIR):

View File

@ -8,7 +8,7 @@
#include <stdbool.h>
// Constants
#define MCCONF_SIGNATURE 347304876
#define MCCONF_SIGNATURE 853550701
#define APPCONF_SIGNATURE 486554156
// Functions

View File

@ -191,9 +191,11 @@ typedef enum {
SENSOR_PORT_MODE_SINCOS,
SENSOR_PORT_MODE_TS5700N8501,
SENSOR_PORT_MODE_TS5700N8501_MULTITURN,
SENSOR_PORT_MODE_MT6816_SPI,
SENSOR_PORT_MODE_MT6816_SPI_HW,
SENSOR_PORT_MODE_AS5x47U_SPI,
SENSOR_PORT_MODE_BISSC
SENSOR_PORT_MODE_BISSC,
SENSOR_PORT_MODE_TLE5014_SSC_SW,
SENSOR_PORT_MODE_TLE5014_SSC_HW,
} sensor_port_mode;
typedef struct {

View File

@ -52,13 +52,48 @@ void spi_bb_deinit(spi_bb_state *s) {
s->has_error = false;
}
void ssc_bb_init(spi_bb_state *s) {
chMtxObjectInit(&s->mutex);
if (s->mosi_gpio && s->nss_gpio && s->sck_gpio) { // TODO: test
palSetPadMode(s->mosi_gpio, s->mosi_pin, PAL_MODE_INPUT_PULLUP);
palSetPadMode(s->sck_gpio, s->sck_pin,
PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
palSetPadMode(s->nss_gpio, s->nss_pin,
PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
}
palClearPad(s->sck_gpio, s->sck_pin);
palSetPad(s->nss_gpio, s->nss_pin);
s->has_started = false;
s->has_error = false;
}
void ssc_bb_deinit(spi_bb_state *s) {
chMtxObjectInit(&s->mutex);
palSetPadMode(s->mosi_gpio, s->miso_pin, PAL_MODE_INPUT_PULLUP);
palSetPadMode(s->sck_gpio, s->sck_pin, PAL_MODE_INPUT_PULLUP);
palSetPadMode(s->nss_gpio, s->nss_pin, PAL_MODE_INPUT_PULLUP);
s->has_started = false;
s->has_error = false;
}
uint8_t spi_bb_exchange_8(spi_bb_state *s, uint8_t x) {
uint8_t rx;
spi_bb_transfer_8(s, &rx, &x, 1);
return rx;
}
void spi_bb_transfer_8(spi_bb_state *s, uint8_t *in_buf, const uint8_t *out_buf, int length) {
void spi_bb_transfer_8(
spi_bb_state *s,
uint8_t *in_buf,
const uint8_t *out_buf,
int length
) {
for (int i = 0; i < length; i++) {
uint8_t send = out_buf ? out_buf[i] : 0xFF;
uint8_t receive = 0;
@ -100,7 +135,12 @@ void spi_bb_transfer_8(spi_bb_state *s, uint8_t *in_buf, const uint8_t *out_buf,
}
}
void spi_bb_transfer_16(spi_bb_state *s, uint16_t *in_buf, const uint16_t *out_buf, int length) {
void spi_bb_transfer_16(
spi_bb_state *s,
uint16_t *in_buf,
const uint16_t *out_buf,
int length
) {
for (int i = 0; i < length; i++) {
uint16_t send = out_buf ? out_buf[i] : 0xFFFF;
uint16_t receive = 0;
@ -140,6 +180,64 @@ void spi_bb_transfer_16(spi_bb_state *s, uint16_t *in_buf, const uint16_t *out_b
}
}
/**
* @brief
* Software data transfer using SSC protocol.
* (SSC = SPI with mosi/miso combined into 1 bidirectional wire)
*
* @param s pointer software spi state
* @param in_buf pointer to empty rx array of uint16_t with same N as length
* @param out_buf pointer to tx array of uint16_t with same N as length
* @param length number of 16 bit transfers
* @param write 0 = read, 1 = write
*/
void ssc_bb_transfer_16(
spi_bb_state *s,
uint16_t *in_buf,
const uint16_t *out_buf,
int length,
bool write
) {
for (int i = 0; i < length; i++) {
uint16_t send = out_buf ? out_buf[i] : 0xFFFF;
uint16_t receive = 0;
//ssc uses mosi for all data
if(write && s->mosi_gpio){
palWritePad(s->mosi_gpio, s->mosi_pin, send >> 15);
palSetPadMode(s->mosi_gpio, s->mosi_pin,
PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
} else {
palSetPadMode(s->mosi_gpio, s->mosi_pin, PAL_MODE_INPUT_PULLUP);
write = false;
}
for (int bit = 0; bit < 16; bit++) {
// Data is put on the data line with the rising edge of SCK
// and read with the falling edge of SCK. (tle5012)
palSetPad(s->sck_gpio, s->sck_pin);
if(write){
palWritePad(s->mosi_gpio, s->mosi_pin, send >> 15);
send <<= 1;
}
spi_bb_delay_short();
palClearPad(s->sck_gpio, s->sck_pin);
spi_bb_delay_short();
// read when clk low
receive <<= 1;
receive |= palReadPad(s->mosi_gpio, s->mosi_pin);
}
if (in_buf) {
in_buf[i] = receive;
}
}
}
void spi_bb_begin(spi_bb_state *s) {
spi_bb_delay();
palClearPad(s->nss_gpio, s->nss_pin);
@ -153,6 +251,7 @@ void spi_bb_end(spi_bb_state *s) {
}
void spi_bb_delay(void) {
// ~1500 ns long
for (volatile int i = 0; i < 6; i++) {
__NOP();
}

View File

@ -25,11 +25,23 @@
#include "stdint.h"
#include "stdbool.h"
enum spi_types{
spi_type_sw, // spi = seperate mosi and miso wires, (hw = hw spi pins)
spi_type_hw,
ssc_type_sw, // ssc = one data wire using mosi pin
ssc_type_hw,
};
typedef struct {
stm32_gpio_t *nss_gpio; int nss_pin;
stm32_gpio_t *sck_gpio; int sck_pin;
stm32_gpio_t *mosi_gpio; int mosi_pin;
stm32_gpio_t *miso_gpio; int miso_pin;
stm32_gpio_t *nss_gpio;
int nss_pin;
stm32_gpio_t *sck_gpio;
int sck_pin;
stm32_gpio_t *mosi_gpio;
int mosi_pin;
stm32_gpio_t *miso_gpio;
int miso_pin;
enum spi_types spi_type;
bool has_started;
bool has_error;
mutex_t mutex;
@ -37,11 +49,15 @@ typedef struct {
void spi_bb_init(spi_bb_state *s);
void spi_bb_deinit(spi_bb_state *s);
void ssc_bb_init(spi_bb_state *s);
void ssc_bb_deinit(spi_bb_state *s);
uint8_t spi_bb_exchange_8(spi_bb_state *s, uint8_t x);
void spi_bb_transfer_8(spi_bb_state *s, uint8_t *in_buf, const uint8_t *out_buf, int length);
void spi_bb_transfer_16(spi_bb_state *s, uint16_t *in_buf, const uint16_t *out_buf, int length);
void ssc_bb_transfer_16(spi_bb_state *s, uint16_t *in_buf, const uint16_t *out_buf, int length, bool write);
void spi_bb_begin(spi_bb_state *s);
void spi_bb_end(spi_bb_state *s);
void spi_bb_delay(void);
void spi_bb_delay_short(void);

View File

@ -25,7 +25,7 @@
#include "datatypes.h"
#include "encoder/encoder_datatype.h"
bool enc_mt6816_init(MT6816_config_t *mt6816_config);
bool enc_mt6816_init(MT6816_config_t *cfg);
void enc_mt6816_deinit(MT6816_config_t *cfg);
void enc_mt6816_routine(MT6816_config_t *cfg);

499
encoder/enc_tle5012.c Normal file
View File

@ -0,0 +1,499 @@
/*
Copyright 2016 - 2022 Benjamin Vedder benjamin@vedder.se
Copyright 2022 Marcos Chaparro mchaparro@powerdesigns.ca
Copyright 2022 Jakub Tomczak
Copyright 2022 Marshall Scholz
This file is part of the VESC firmware.
The VESC firmware is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
The VESC firmware is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Encoder driver for TLE5012
https://www.infineon.com/dgdl/Infineon-TLE5012B_Exxxx-DataSheet-v02_01-EN.pdf?fileId=db3a304334fac4c601350f31c43c433f
*/
#include "enc_mt6816.h"
#include "ch.h"
#include "hal.h"
#include "stm32f4xx_conf.h"
#include "hw.h"
#include "mc_interface.h"
#include "utils.h"
#include "spi_bb.h"
#include "timer.h"
#include <math.h>
#include <string.h>
// Bitmasks for several read and write functions
#define TLE5012_SYSTEM_ERROR_MASK 0x4000 //!< System error masks for safety words
#define TLE5012_INTERFACE_ERROR_MASK 0x2000 //!< Interface error masks for safety words
#define TLE5012_INV_ANGLE_ERROR_MASK 0x1000 //!< Angle error masks for safety words
#define TLE5012_CRC_POLYNOMIAL 0x1D //!< values used for calculating the CRC
#define TLE5012_CRC_SEED 0xFF
enum tle5012_registers {
REG_STAT = 0, //!< STAT status register
REG_ACSTAT = 1, //!< ACSTAT activation status register
REG_AVAL = 2, //!< AVAL angle value register
REG_ASPD = 3, //!< ASPD angle speed register
REG_AREV = 4, //!< AREV angle revolution register
REG_FSYNC = 5, //!< FSYNC frame synchronization register
REG_MOD_1 = 6, //!< MOD_1 interface mode1 register
REG_SIL = 7, //!< SIL register
REG_MOD_2 = 8, //!< MOD_2 interface mode2 register
REG_MOD_3 = 9, //!< MOD_3 interface mode3 register
REG_OFFX = 10, //!< OFFX offset x
REG_OFFY = 11, //!< OFFY offset y
REG_SYNCH = 12, //!< SYNCH synchronicity
REG_IFAB = 13, //!< IFAB register
REG_MOD_4 = 14, //!< MOD_4 interface mode4 register
REG_TCO_Y = 15, //!< TCO_Y temperature coefficient register
REG_ADC_X = 16, //!< ADC_X ADC X-raw value
REG_ADC_Y = 17, //!< ADC_Y ADC Y-raw value
REG_D_MAG = 18, //!< D_MAG angle vector magnitude
REG_T_RAW = 19, //!< T_RAW temperature sensor raw-value
REG_IIF_CNT = 20, //!< IIF_CNT IIF counter value
REG_T25O = 21, //!< T25O temperature 25°c offset value
};
typedef enum ssc_direction {
SSC_READ = true,
SSC_WRITE = false
} ssc_direction;
bool enc_tle5012_setup(TLE5012_config_t *cfg);
tle5012_errortypes enc_tle5012_transfer(TLE5012_config_t *cfg, uint8_t address, uint16_t *data, ssc_direction read, bool safe);
uint8_t crc8(uint8_t *data, uint8_t length);
tle5012_errortypes checkSafety(uint16_t command, uint16_t safetyword, const uint16_t *readreg, uint16_t length);
bool enc_tle5012_init_sw_ssc(TLE5012_config_t *cfg) {
// software ssc
memset(&cfg->state, 0, sizeof(TLE5012_state));
spi_bb_init(&(cfg->sw_spi));
cfg->state.last_status_error = 0;
cfg->state.spi_error_rate = 0.0;
cfg->state.encoder_no_magnet_error_rate = 0.0;
return enc_tle5012_setup(cfg);
}
bool enc_tle5012_init_hw_ssc(TLE5012_config_t *cfg) {
// software ssc for now using hw spi pins
memset(&cfg->state, 0, sizeof(TLE5012_state));
spi_bb_init(&(cfg->sw_spi));
cfg->state.last_status_error = 0;
cfg->state.spi_error_rate = 0.0;
cfg->state.encoder_no_magnet_error_rate = 0.0;
return enc_tle5012_setup(cfg);
}
void enc_tle5012_deinit(TLE5012_config_t *cfg) {
// sw spi
spi_bb_deinit(&(cfg->sw_spi));
cfg->state.last_enc_angle = 0.0;
cfg->state.spi_error_rate = 0.0;
}
// set writable registers to known state and check communication.
bool enc_tle5012_setup(TLE5012_config_t *cfg) {
/*
// TLE5012B E1000 (IIF) configuration:
IIF-type: E1000
The TLE5012B E1000 is preconfigured for Incremental Interface and fast angle update rate (42.7 μs).
It is most suitable for BLDC motor commutation.
Incremental Interface A/B mode.
12bit mode, one count per 0.088° angle step.
Absolute count enabled.
Autocalibration mode 1 enabled.
Prediction disabled.
Hysteresis set to 0.703°.
IFA/IFB/IFC pins set to push-pull output.
SSC interfaces DATA pin set to push-pull output.
IFA/IFB/IFC pins set to strong driver, DATA pin set to strong driver, fast edge.
Voltage spike filter on input pads disabled.
- Interface Mode1 Register
fir_md = 0b01 // Update Rate Setting (Filter Decimation), 42.7 μs (minimum)
clk_sel = 0 // Clock Source Select, internal
dspu_hold = 0 // DSPU in normal schedule operation, no watchdog reset
iif_mod = 0b01 // Incremental Interface Mode, A/B operation with Index on IFC pin
Offset = 0x06
mask = 0b11 00000000 1 0 1 11 // reserved unset only
word = 0b01 00000000 0 0 0 01
- Interface Mode2 Register
predict: 0 // prediction disabled
autocal = 0b01 //auto-cal. mode 1: update every angle update cycle
// change autocal to 0b00? (no auto-calibration)
Offset = 0x08
mask = 0b0 1111111111 1 1 11
word = 0b0 1111111111 0 0 01
- Interface Mode3 Register
spikef = 0 // Analog Spike Filter of Input Pads, disabled
ssc_od = 0 // SSC-Interface Data Pin Output Mode, Push-Pull
PAD_drv = 00 // Configuration of Pad-Driver,
// IFA/IFB/IFC: strong driver, DATA: strong driver, fast edge
Offset = 0x09
mask = 0b00000000000 1 1 11 // can overwrite ang base to 0?
word = 0b00000000000 0 0 00
- TCO_Y // nothing derivate-specific
sbist = 1// built in self test on startup
crc = crc of parameters if autocalibrate not set.
- IFAB Register
fir_udr = 1 // FIR Update Rate, FIR_MD = 01 (42.7 μs)
ifab_od = 0 // IFA,IFB,IFC Output Mode, Push-Pull
ifab_hyst = 0b11 // HSM and IIF Mode: Hysteresis, 0.70° (max)
mask = 0b00000000000 1 1 11
word = 0b00000000000 1 0 11
- Interface Mode4 Register
hsm_plp = 0b0001 // Incremental Interface Mode: Absolute Count, absolute count enabled
ifab_res = 0b00 // Incremental Interface Mode: IIF resolution, 12bit, 0.088° step
if_md = 0b00 // Interface Mode on IFA,IFB,IFC, IIF
mask = 0b0000000 1111 11 11
word = 0b0000000 0001 00 00
*/
// set up control registers to be identical across tle5012 variants using above settings
tle5012_errortypes errorCheck = 0;
uint16_t tleregister;
// Interface Mode1
errorCheck = errorCheck && enc_tle5012_transfer(cfg, 0x06, &tleregister, SSC_READ, true);
tleregister = tleregister & ~0b110000000010111; // mask (1 = cleared)
tleregister = tleregister | 0b010000000000001; // set bits
errorCheck = errorCheck && enc_tle5012_transfer(cfg, 0x06, &tleregister, SSC_WRITE, true);
// Interface Mode2
errorCheck = errorCheck && enc_tle5012_transfer(cfg, 0x08, &tleregister, SSC_READ, true);
tleregister = tleregister & ~0b011111111111111;
tleregister = tleregister | 0b011111111110001;
errorCheck = errorCheck && enc_tle5012_transfer(cfg, 0x08, &tleregister, SSC_WRITE, true);
// Interface Mode3
errorCheck = errorCheck && enc_tle5012_transfer(cfg, 0x09, &tleregister, SSC_READ, true);
tleregister = tleregister & ~0b000000000001111;
tleregister = tleregister | 0b000000000000000;
errorCheck = errorCheck && enc_tle5012_transfer(cfg, 0x09, &tleregister, SSC_WRITE, true);
// IFAB Register
errorCheck = errorCheck && enc_tle5012_transfer(cfg, 0x0D, &tleregister, SSC_READ, true);
tleregister = tleregister & ~0b000000000001111;
tleregister = tleregister | 0b000000000001011;
errorCheck = errorCheck && enc_tle5012_transfer(cfg, 0x0D, &tleregister, SSC_WRITE, true);
// Interface Mode4
errorCheck = errorCheck && enc_tle5012_transfer(cfg, 0x0E, &tleregister, SSC_READ, true);
tleregister = tleregister & ~0b000000011111111;
tleregister = tleregister | 0b000000000010000;
errorCheck = errorCheck && enc_tle5012_transfer(cfg, 0x0E, &tleregister, SSC_WRITE, true);
cfg->state.last_status_error = errorCheck;
// setup will not succeed unless we can talk to sensor and magnet detected
if (errorCheck != NO_ERROR){
return false;
}
return true;
}
void enc_tle5012_routine(TLE5012_config_t *cfg) {
float timestep = timer_seconds_elapsed_since(cfg->state.last_update_time);
if (timestep > 1.0) {
timestep = 1.0;
}
cfg->state.last_update_time = timer_time_now();
uint16_t rx_data;
uint8_t tle_status = enc_tle5012_transfer(cfg, REG_AVAL, &rx_data, SSC_READ, true); // define register names values?
cfg->state.last_status_error = tle_status;
if (tle_status == NO_ERROR ){
uint16_t pos = rx_data & 0x7FFF;
cfg->state.last_enc_angle = (float) pos * (360.0 / 32768.0); // 2^15 = 32768.0
UTILS_LP_FAST(cfg->state.spi_error_rate, 0.0, timestep);
}else{
if (tle_status != CRC_ERROR ) { // if not just a crc error
// read/clear error reg
uint16_t status_reg_dat;
enc_tle5012_transfer(cfg, REG_STAT, &status_reg_dat, SSC_READ, true);
}
++cfg->state.spi_error_cnt;
UTILS_LP_FAST(cfg->state.spi_error_rate, 1.0, timestep);
}
}
// get tle5012 temp in celsius.
tle5012_errortypes enc_tle5012_get_temperature(TLE5012_config_t *cfg, double *temperature) {
uint16_t rawTemp = 0;
uint8_t tle_status_err = enc_tle5012_transfer(cfg, REG_FSYNC, &rawTemp, SSC_READ, true);
// extract 9 temp bits
rawTemp = (rawTemp & (0x01FF));
//check if the value received is positive or negative
if (rawTemp & 0x0100) {
rawTemp = rawTemp - 0x0200; // 9 bit compliment
}
// temperature = (rawTemp + TEMP_OFFSET) / (TEMP_DIV);
*temperature = ((((int16_t) rawTemp) + 152.0) / (2.776));
return (tle_status_err);
}
// may not be working properly. inconsistant values.
// Unsigned Angle Vector Magnitude after X, Y error compensation (due to temperature).
tle5012_errortypes enc_tle5012_get_magnet_magnitude(TLE5012_config_t *cfg, uint16_t *magnitude) {
uint16_t rawMag = 0;
uint8_t tle_status_err = enc_tle5012_transfer(cfg, REG_D_MAG, &rawMag, SSC_READ, true);
// extract 10 mag bits
rawMag = (rawMag && (0x03FF));
// MAG = (SQRT(X*X+Y*Y))/64; X,Y = raw gmr adc values
*magnitude = (uint16_t) rawMag;
return (tle_status_err);
}
tle5012_errortypes enc_tle5012_transfer(TLE5012_config_t *cfg, uint8_t address, uint16_t *data, ssc_direction read, bool safety) {
// command word:
// [15] = rw, 1=read <- first bit transmitted
// [14..11] = lock, 0000 (don't need this if not writing)
// [10] = Update-Register Access, 0: Access to current values, 1: values in buffer
// [9..4] = address, status=0x00, angle=0x02, speed=0x03
// [3..0] = 4-bit Number of Data Words (if bits set to 0000B, no safety word is provided)
const uint8_t upd = 0b0;
uint16_t safety_word;
uint16_t safeword;
if (safety) {
safeword = 0b001 << 0; // SAFE_0, just safety word
} else {
safeword = 0b000 << 0; // SAFE_0, no safety word
}
uint16_t command_word = (read << 15) | (upd << 10) | (address << 4)| (safeword << 0);
spi_bb_begin(&(cfg->sw_spi));
ssc_bb_transfer_16(&(cfg->sw_spi), &safety_word, &command_word, 1, 1); // send command
ssc_bb_transfer_16(&(cfg->sw_spi), data, data, 1, !read); // read register
if (safety) {
ssc_bb_transfer_16(&(cfg->sw_spi), &safety_word, 0, 1, false); // read safety word
}
spi_bb_end(&(cfg->sw_spi));
tle5012_errortypes status = checkSafety(command_word, safety_word, data, 1);
return status;
}
/*!
* Function for calculation the CRC.
* @param data byte long data for CRC check
* @param length length of data
* @return returns 8bit CRC
*/
uint8_t crc8(uint8_t *data, uint8_t length)
{
uint32_t crc;
int16_t i, bit;
crc = TLE5012_CRC_SEED;
for (i = 0; i < length; i++)
{
crc ^= data[i];
for (bit = 0; bit < 8; bit++)
{
if ((crc & 0x80) != 0)
{
crc <<= 1;
crc ^= TLE5012_CRC_POLYNOMIAL;
}else{
crc <<= 1;
}
}
}
return ((~crc) & TLE5012_CRC_SEED);
}
// check crc and safety word
tle5012_errortypes checkSafety(uint16_t command, uint16_t safetyword, const uint16_t *readreg, uint16_t length){
/*
safety word:
[15]:Indication of chip reset or watchdog overflow (resets after readout) via SSC
[14]: System error
[13]: Interface access error
[12]: Invalid angle value (produce vesc fault if 1)
[11..8]: Sensor number response indicator
[7..0]: crc
*/
tle5012_errortypes errorCheck;
if (!((safetyword) & TLE5012_SYSTEM_ERROR_MASK)) {
errorCheck = SYSTEM_ERROR;
// resetSafety();
} else if (!((safetyword) & TLE5012_INTERFACE_ERROR_MASK)) {
errorCheck = INTERFACE_ACCESS_ERROR;
//resetSafety();
} else if (!((safetyword) & TLE5012_INV_ANGLE_ERROR_MASK)) {
errorCheck = INVALID_ANGLE_ERROR;
//resetSafety();
} else {
//resetSafety();
uint16_t lengthOfTemp = length * 2 + 2;
uint8_t temp[lengthOfTemp];
temp[0] = (uint8_t) (command >> 8);
temp[1] = (uint8_t) (command);
for (uint16_t i = 0; i < length; i++) {
temp[2 + 2 * i] = (uint8_t) (readreg[i] >> 8);
temp[2 + 2 * i + 1] = (uint8_t) (readreg[i]);
}
volatile uint8_t crcReceivedFinal = (uint8_t) safetyword;
volatile uint8_t crc = crc8(temp, lengthOfTemp);
if (crc == crcReceivedFinal) {
errorCheck = NO_ERROR;
} else {
errorCheck = CRC_ERROR;
// resetSafety();
}
}
return errorCheck;
}
// const Reg::BitField_t Reg::bitFields[] =
// {
// {REG_ACCESS_RU, REG_STAT, 0x2, 1, 0x00, 0}, //!< 00 bits 0:0 SRST status watch dog
// {REG_ACCESS_R, REG_STAT, 0x2, 1, 0x00, 0}, //!< 01 bits 1:1 SWD status watch dog
// {REG_ACCESS_R, REG_STAT, 0x4, 2, 0x00, 0}, //!< 02 bits 2:2 SVR status voltage regulator
// {REG_ACCESS_R, REG_STAT, 0x8, 3, 0x00, 0}, //!< 03 bits 3:3 SFUSE status fuses
// {REG_ACCESS_R, REG_STAT, 0x10, 4, 0x00, 0}, //!< 04 bits 4:4 SDSPU status digital signal processing unit
// {REG_ACCESS_RU, REG_STAT, 0x20, 5, 0x00, 0}, //!< 05 bits 5:5 SOV status overflow
// {REG_ACCESS_RU, REG_STAT, 0x40, 6, 0x00, 0}, //!< 06 bits 6:6 SXYOL status X/Y data out limit
// {REG_ACCESS_RU, REG_STAT, 0x80, 7, 0x00, 0}, //!< 07 bits 7:7 SMAGOL status magnitude out limit
// {REG_ACCESS_RES, REG_STAT, 0x100, 8, 0x00, 0}, //!< 08 bits 8:8 reserved
// {REG_ACCESS_R, REG_STAT, 0x200, 9, 0x00, 0}, //!< 09 bits 9:9 SADCT status ADC test
// {REG_ACCESS_R, REG_STAT, 0x400, 10, 0x00, 0}, //!< 10 bits 10:10 SROM status ROM
// {REG_ACCESS_RU, REG_STAT, 0x800, 11, 0x00, 0}, //!< 11 bits 11:11 NOGMRXY no valid GMR XY Values
// {REG_ACCESS_RU, REG_STAT, 0x1000, 12, 0x00, 0}, //!< 12 bits 12:12 NOGMRA no valid GMR Angle Value
// {REG_ACCESS_RW, REG_STAT, 0x6000, 13, 0x00, 0}, //!< 13 bits 14:13 SNR slave number
// {REG_ACCESS_RU, REG_STAT, 0x8000, 15, 0x00, 0}, //!< 14 bits 15:15 RDST read status
// {REG_ACCESS_RW, REG_ACSTAT, 0x1, 0, 0x00, 1}, //!< 15 bits 0:0 ASRST Activation of Hardware Reset
// {REG_ACCESS_RWU, REG_ACSTAT, 0x2, 1, 0x00, 1}, //!< 16 bits 1:1 ASWD Enable DSPU Watch dog
// {REG_ACCESS_RWU, REG_ACSTAT, 0x4, 2, 0x00, 1}, //!< 17 bits 2:2 ASVR Enable Voltage regulator Check
// {REG_ACCESS_RWU, REG_ACSTAT, 0x8, 3, 0x00, 1}, //!< 18 bits 3:3 ASFUSE Activation Fuse CRC
// {REG_ACCESS_RWU, REG_ACSTAT, 0x10, 4, 0x00, 1}, //!< 19 bits 4:4 ASDSPU Activation DSPU BIST
// {REG_ACCESS_RWU, REG_ACSTAT, 0x20, 5, 0x00, 1}, //!< 20 bits 5:5 ASOV Enable of DSPU Overflow Check
// {REG_ACCESS_RWU, REG_ACSTAT, 0x40, 6, 0x00, 1}, //!< 21 bits 6:6 ASVECXY Activation of X,Y Out of Limit-Check
// {REG_ACCESS_RWU, REG_ACSTAT, 0x80, 7, 0x00, 1}, //!< 22 bits 7:7 ASVEGMAG Activation of Magnitude Check
// {REG_ACCESS_RES, REG_ACSTAT, 0x100, 8, 0x00, 1}, //!< 23 bits 8:8 Reserved
// {REG_ACCESS_RWU, REG_ACSTAT, 0x200, 9, 0x00, 1}, //!< 24 bits 9:9 ASADCT Enable ADC Test vector Check
// {REG_ACCESS_RWU, REG_ACSTAT, 0x400, 10, 0x00, 1}, //!< 25 bits 10:10 ASFRST Activation of Firmware Reset
// {REG_ACCESS_RES, REG_ACSTAT, 0xF800, 11, 0x00, 1}, //!< 26 bits 15:11 Reserved
// {REG_ACCESS_RU, REG_AVAL, 0x7FFF, 0, 0x00, 2}, //!< 27 bits 14:0 ANGVAL Calculated Angle Value (signed 15-bit)
// {REG_ACCESS_R, REG_AVAL, 0x8000, 15, 0x00, 2}, //!< 28 bits 15:15 RDAV Read Status, Angle Value
// {REG_ACCESS_RU, REG_ASPD, 0x7FFF, 0, 0x00, 3}, //!< 29 bits 14:0 ANGSPD Signed value, where the sign bit [14] indicates the direction of the rotation
// {REG_ACCESS_R, REG_ASPD, 0x8000, 15, 0x00, 3}, //!< 30 bits 15:15 RDAS Read Status, Angle Speed
// {REG_ACCESS_RU, REG_AREV, 0xFF, 0, 0x00, 4}, //!< 31 bits 8:0 REVOL Revolution counter. Increments for every full rotation in counter-clockwise direction
// {REG_ACCESS_RWU, REG_AREV, 0x7E00, 9, 0x00, 4}, //!< 32 bits 14:9 FCNT Internal frame counter. Increments every update period
// {REG_ACCESS_R, REG_AREV, 0x8000, 15, 0x00, 4}, //!< 33 its 15:15 RDREV Read Status, Revolution
// {REG_ACCESS_RWU, REG_FSYNC, 0xFF, 0, 0x00, 5}, //!< 34 bits 8:0 TEMPR Signed offset compensated temperature value
// {REG_ACCESS_RU, REG_FSYNC, 0xFE00, 9, 0x00, 5}, //!< 35 bits 15:9 FSYNC Frame Synchronization Counter Value
// {REG_ACCESS_RW, REG_MOD_1, 0x3, 0, 0x00, 6}, //!< 36 bits 1:0 IIFMOD Incremental Interface Mode
// {REG_ACCESS_RW, REG_MOD_1, 0x4, 2, 0x00, 6}, //!< 37 bits 2:2 DSPUHOLD if DSPU is on hold, no watch dog reset is performed by DSPU
// {REG_ACCESS_RES, REG_MOD_1, 0x8, 3, 0x00, 6}, //!< 38 bits 3:3 Reserved1
// {REG_ACCESS_RW, REG_MOD_1, 0x10, 4, 0x00, 6}, //!< 39 bits 4:4 CLKSEL switch to external clock at start-up only
// {REG_ACCESS_RES, REG_MOD_1, 0x3FE0, 5, 0x00, 6}, //!< 40 bits 13:5 Reserved2
// {REG_ACCESS_RW, REG_MOD_1, 0x6000, 13, 0x00, 6}, //!< 41 bits 15:14 FIRMD Update Rate Setting
// {REG_ACCESS_RW, REG_SIL, 0x7, 0, 0x00, 7}, //!< 42 bits 2:0 ADCTVX Test vector X
// {REG_ACCESS_RW, REG_SIL, 0x38, 3, 0x00, 7}, //!< 43 bits 5:3 ADCTVY Test vector Y
// {REG_ACCESS_RW, REG_SIL, 0x40, 6, 0x00, 7}, //!< 44 bits 6:6 ADCTVEN Sensor elements are internally disconnected and test voltages are connected to ADCs
// {REG_ACCESS_RES, REG_SIL, 0x380, 7, 0x00, 7}, //!< 45 bits 9:7 Reserved1
// {REG_ACCESS_RW, REG_SIL, 0x400, 10, 0x00, 7}, //!< 46 bits 10:10 FUSEREL Triggers reload of default values from laser fuses into configuration registers
// {REG_ACCESS_RES, REG_SIL, 0x3800, 11, 0x00, 7}, //!< 47 bits 13:11 Reserved2
// {REG_ACCESS_RW, REG_SIL, 0x4000, 14, 0x00, 7}, //!< 48 bits 14:14 FILTINV the X- and Y-signals are inverted. The angle output is then shifted by 180°
// {REG_ACCESS_RW, REG_SIL, 0x8000, 15, 0x00, 7}, //!< 49 bits 15:15 FILTPAR the raw X-signal is routed also to the raw Y-signal input of the filter so SIN and COS signal should be identical
// {REG_ACCESS_RW, REG_MOD_2, 0x3, 0, 0x00, 8}, //!< 50 bits 1:0 AUTOCAL Automatic calibration of offset and amplitude synchronicity for applications with full-turn
// {REG_ACCESS_RW, REG_MOD_2, 0x4, 2, 0x00, 8}, //!< 51 bits 2:2 PREDICT Prediction of angle value based on current angle speed
// {REG_ACCESS_RW, REG_MOD_2, 0x8, 3, 0x00, 8}, //!< 52 bits 3:3 ANGDIR Inverts angle and angle speed values and revolution counter behavior
// {REG_ACCESS_RW, REG_MOD_2, 0x7FF0, 4, 0x00, 8}, //!< 53 bits 14:4 ANGRANGE Changes the representation of the angle output by multiplying the output with a factor ANG_RANGE/128
// {REG_ACCESS_RES, REG_MOD_2, 0x8000, 15, 0x00, 8}, //!< 54 bits 15:15 Reserved1
// {REG_ACCESS_RW, REG_MOD_3, 0x3, 0, 0x00, 9}, //!< 55 bits 1:0 PADDRV Configuration of Pad-Driver
// {REG_ACCESS_RW, REG_MOD_3, 0x4, 2, 0x00, 9}, //!< 56 bits 2:2 SSCOD SSC-Interface Data Pin Output Mode
// {REG_ACCESS_RW, REG_MOD_3, 0x8, 3, 0x00, 9}, //!< 57 bits 3:3 SPIKEF Filters voltage spikes on input pads (IFC, SCK and CSQ)
// {REG_ACCESS_RW, REG_MOD_3, 0xFFF0, 4, 0x00, 9}, //!< 58 bits 15:4 ANG_BASE Sets the 0° angle position (12 bit value). Angle base is factory-calibrated to make the 0° direction parallel to the edge of the chip
// {REG_ACCESS_RES, REG_OFFX, 0xF, 0, 0x00, 10}, //!< 59 bits 3:0 Reserved1
// {REG_ACCESS_RW, REG_OFFX, 0xFFF0, 4, 0x00, 10}, //!< 60 bits 15:4 XOFFSET 12-bit signed integer value of raw X-signal offset correction at 25°C
// {REG_ACCESS_RES, REG_OFFY, 0xF, 0, 0x00, 11}, //!< 61 bits 3:0 Reserved1
// {REG_ACCESS_RW, REG_OFFY, 0xFFF0, 4, 0x00, 11}, //!< 62 bits 15:4 YOFFSET 12-bit signed integer value of raw Y-signal offset correction at 25°C
// {REG_ACCESS_RES, REG_SYNCH, 0xF, 0, 0x00, 12}, //!< 63 bits 3:0 Reserved1
// {REG_ACCESS_RW, REG_SYNCH, 0xFFF0, 4, 0x00, 12}, //!< 64 bits 15:4 SYNCH 12-bit signed integer value of amplitude synchronicity
// {REG_ACCESS_RW, REG_IFAB, 0x3, 0, 0x00, 13}, //!< 65 bits 1:0 IFADHYST Hysteresis (multi-purpose)
// {REG_ACCESS_RW, REG_IFAB, 0x4, 2, 0x00, 13}, //!< 66 bits 2:2 IFABOD IFA,IFB,IFC Output Mode
// {REG_ACCESS_RW, REG_IFAB, 0x8, 3, 0x00, 13}, //!< 67 bits 3:3 FIRUDR Initial filter update rate (FIR)
// {REG_ACCESS_RW, REG_IFAB, 0xFFF0, 4, 0x00, 13}, //!< 68 bits 15:4 ORTHO Orthogonality Correction of X and Y Components
// {REG_ACCESS_RW, REG_MOD_4, 0x3, 0, 0x00, 14}, //!< 69 bits 1:0 IFMD Interface Mode on IFA,IFB,IFC
// {REG_ACCESS_RES, REG_MOD_4, 0x4, 2, 0x00, 14}, //!< 70 bits 2:2 Reserved1
// {REG_ACCESS_RW, REG_MOD_4, 0x18, 3, 0x00, 14}, //!< 71 bits 4:3 IFABRES IIF resolution (multi-purpose)
// {REG_ACCESS_RW, REG_MOD_4, 0x1E0, 5, 0x00, 14}, //!< 72 bits 8:5 HSMPLP Hall Switch mode (multi-purpose)
// {REG_ACCESS_RW, REG_MOD_4, 0x7E00, 9, 0x00, 14}, //!< 73 bits 15:9 TCOXT 7-bit signed integer value of X-offset temperature coefficient
// {REG_ACCESS_RW, REG_TCO_Y, 0x7F, 0, 0x00, 15}, //!< 74 bits 7:0 CRCPAR CRC of Parameters
// {REG_ACCESS_RW, REG_TCO_Y, 0x80, 8, 0x00, 15}, //!< 75 bits 8:8 SBIST Startup-BIST
// {REG_ACCESS_RW, REG_TCO_Y, 0x7E00, 9, 0x00, 15}, //!< 76 bits 15:9 TCOYT 7-bit signed integer value of Y-offset temperature coefficient
// {REG_ACCESS_R, REG_ADC_X, 0xFFFF, 0, 0x00, 16}, //!< 77 bits 15:0 ADCX ADC value of X-GMR
// {REG_ACCESS_R, REG_ADC_Y, 0xFFFF, 0, 0x00, 17}, //!< 78 bits 15:0 ADCY ADC value of Y-GMR
// {REG_ACCESS_RU, REG_D_MAG, 0x3FF, 0, 0x00, 18}, //!< 79 bits 9:0 MAG Unsigned Angle Vector Magnitude after X, Y error compensation (due to temperature)
// {REG_ACCESS_RES, REG_D_MAG, 0xFC00, 10, 0x00, 18}, //!< 80 bits 15:10 Reserved1
// {REG_ACCESS_RU, REG_T_RAW, 0x3FF, 0, 0x00, 19}, //!< 81 bits 9:0 TRAW Temperature Sensor Raw-Value at ADC without offset
// {REG_ACCESS_RES, REG_T_RAW, 0xFC00, 10, 0x00, 19}, //!< 82 bits 14:10 Reserved1
// {REG_ACCESS_RU, REG_T_RAW, 0x8000, 15, 0x00, 19}, //!< 83 bits 15:15 TTGL Temperature Sensor Raw-Value Toggle toggles after every new temperature value
// {REG_ACCESS_RU, REG_IIF_CNT, 0x7FFF, 0, 0x00, 20}, //!< 84 bits 14:0 IIFCNT 14 bit counter value of IIF increments
// {REG_ACCESS_RES, REG_IIF_CNT, 0x8000, 15, 0x00, 20}, //!< 85 bits 15:14 Reserved1
// {REG_ACCESS_R, REG_T25O, 0x1FFF, 0, 0x00, 21}, //!< 86 bit 8:0 T250 Signed offset value at 25°C temperature; 1dig=0.36°C
// {REG_ACCESS_RES, REG_T25O, 0xFE00, 9, 0x00, 21}, //!< 87 bits 15:9 Reserved1
// };

38
encoder/enc_tle5012.h Normal file
View File

@ -0,0 +1,38 @@
/*
Copyright 2016 - 2022 Benjamin Vedder benjamin@vedder.se
Copyright 2022 Marcos Chaparro mchaparro@powerdesigns.ca
Copyright 2022 Jakub Tomczak
This file is part of the VESC firmware.
The VESC firmware is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
The VESC firmware is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ENC_TLE5012_H_
#define ENC_TLE5012_H_
#include "datatypes.h"
#include "encoder/encoder_datatype.h"
bool enc_tle5012_init_sw_ssc(TLE5012_config_t *cfg);
bool enc_tle5012_init_hw_ssc(TLE5012_config_t *cfg);
void enc_tle5012_deinit(TLE5012_config_t *cfg);
void enc_tle5012_routine(TLE5012_config_t *cfg);
tle5012_errortypes enc_tle5012_get_temperature(TLE5012_config_t *cfg, double *temperature);
tle5012_errortypes enc_tle5012_get_magnet_magnitude(TLE5012_config_t *cfg, uint16_t *magnitude);
// Macros
#define TLE5012_LAST_ANGLE(cfg) ((cfg)->state.last_enc_angle)
#endif /* ENC_TLE5012_H_ */

View File

@ -79,7 +79,7 @@ bool encoder_init(volatile mc_configuration *conf) {
res = true;
} break;
case SENSOR_PORT_MODE_MT6816_SPI: {
case SENSOR_PORT_MODE_MT6816_SPI_HW: {
SENSOR_PORT_5V();
if (!enc_mt6816_init(&encoder_cfg_mt6816)) {
@ -93,6 +93,63 @@ bool encoder_init(volatile mc_configuration *conf) {
res = true;
} break;
// ssc (3 wire) sw spi on hall pins
case SENSOR_PORT_MODE_TLE5014_SSC_SW: {
SENSOR_PORT_5V();
// reuse global config, so must set up complete ssc config
spi_bb_state sw_ssc = {
HW_HALL_ENC_GPIO3, HW_HALL_ENC_PIN3, // nss
HW_HALL_ENC_GPIO1, HW_HALL_ENC_PIN1, // sck
HW_HALL_ENC_GPIO2, HW_HALL_ENC_PIN2, // mosi
HW_HALL_ENC_GPIO2, HW_HALL_ENC_PIN2, // miso
ssc_type_sw,
0, // has_started
0, // has_error
{{NULL, NULL}, NULL, NULL} // Mutex
};
encoder_cfg_tle5012.sw_spi = sw_ssc;
if (!enc_tle5012_init_sw_ssc(&encoder_cfg_tle5012)) {
encoder_type_now = ENCODER_TYPE_NONE;
return false;
}
encoder_type_now = ENCODER_TYPE_TLE5012;
timer_start(4000); // slow down sw spi as transactions long
res = true;
} break;
// ssc (3 wire) hw spi w dma (sw spi using hw spi pins for now)
case SENSOR_PORT_MODE_TLE5014_SSC_HW: {
SENSOR_PORT_5V();
// reuse global config, so must set up complete ssc config
spi_bb_state sw_ssc = {
HW_SPI_PORT_NSS, HW_SPI_PIN_NSS, // nss
HW_SPI_PORT_SCK, HW_SPI_PIN_SCK, // sck
HW_SPI_PORT_MOSI, HW_SPI_PIN_MOSI, // mosi
HW_SPI_PORT_MOSI, HW_SPI_PIN_MOSI, // miso (shared dat line)
ssc_type_sw,
0, // has_started
0, // has_error
{{NULL, NULL}, NULL, NULL} // Mutex
};
encoder_cfg_tle5012.sw_spi = sw_ssc;
if (!enc_tle5012_init_hw_ssc(&encoder_cfg_tle5012)) {
encoder_type_now = ENCODER_TYPE_NONE;
return false;
}
encoder_type_now = ENCODER_TYPE_TLE5012;
// timer_start(10000);
timer_start(4000);
res = true;
} break;
case SENSOR_PORT_MODE_AD2S1205: {
SENSOR_PORT_5V();
@ -186,7 +243,7 @@ bool encoder_init(volatile mc_configuration *conf) {
terminal_register_command_callback(
"encoder",
"Prints the status of the AS5047, AS5x47U, AD2S1205, or TS5700N8501 encoder.",
"Prints the status of the AS5047, AS5x47U, AD2S1205, TLE5012, MT6816, or TS5700N8501 encoder.",
0,
terminal_encoder);
@ -214,6 +271,8 @@ void encoder_deinit(void) {
enc_as504x_deinit(&encoder_cfg_as504x);
} else if (encoder_type_now == ENCODER_TYPE_MT6816) {
enc_mt6816_deinit(&encoder_cfg_mt6816);
} else if (encoder_type_now == ENCODER_TYPE_TLE5012) {
enc_tle5012_deinit(&encoder_cfg_tle5012);
} else if (encoder_type_now == ENCODER_TYPE_AD2S1205_SPI) {
enc_ad2s1205_deinit(&encoder_cfg_ad2s1205);
} else if (encoder_type_now == ENCODER_TYPE_ABI) {
@ -236,6 +295,8 @@ float encoder_read_deg(void) {
return AS504x_LAST_ANGLE(&encoder_cfg_as504x);
} else if (encoder_type_now == ENCODER_TYPE_MT6816) {
return MT6816_LAST_ANGLE(&encoder_cfg_mt6816);
} else if (encoder_type_now == ENCODER_TYPE_TLE5012) {
return TLE5012_LAST_ANGLE(&encoder_cfg_tle5012);
} else if (encoder_type_now == ENCODER_TYPE_AD2S1205_SPI) {
return AD2S1205_LAST_ANGLE(&encoder_cfg_ad2s1205);
} else if (encoder_type_now == ENCODER_TYPE_ABI) {
@ -322,12 +383,23 @@ void encoder_check_faults(volatile mc_configuration *m_conf, bool is_second_moto
}
break;
case SENSOR_PORT_MODE_MT6816_SPI:
case SENSOR_PORT_MODE_MT6816_SPI_HW:
if (encoder_cfg_mt6816.state.encoder_no_magnet_error_rate > 0.05) {
mc_interface_fault_stop(FAULT_CODE_ENCODER_NO_MAGNET, is_second_motor, false);
}
break;
case SENSOR_PORT_MODE_TLE5014_SSC_HW:
case SENSOR_PORT_MODE_TLE5014_SSC_SW:
if (encoder_cfg_tle5012.state.spi_error_rate > 0.10) {
mc_interface_fault_stop(FAULT_CODE_ENCODER_FAULT, is_second_motor, false);
}
if (encoder_cfg_tle5012.state.last_status_error != NO_ERROR &&
encoder_cfg_tle5012.state.last_status_error != CRC_ERROR) {
mc_interface_fault_stop(FAULT_CODE_ENCODER_FAULT, is_second_motor, false);
} // allow some crc errors below 10% error rate
break;
case SENSOR_PORT_MODE_SINCOS:
if (encoder_cfg_sincos.state.signal_low_error_rate > 0.05) {
mc_interface_fault_stop(FAULT_CODE_ENCODER_SINCOS_BELOW_MIN_AMPLITUDE, is_second_motor, false);
@ -398,6 +470,10 @@ void encoder_tim_isr(void) {
enc_mt6816_routine(&encoder_cfg_mt6816);
break;
case ENCODER_TYPE_TLE5012:
enc_tle5012_routine(&encoder_cfg_tle5012);
break;
case ENCODER_TYPE_AD2S1205_SPI:
enc_ad2s1205_routine(&encoder_cfg_ad2s1205);
break;
@ -422,7 +498,8 @@ static void terminal_encoder(int argc, const char **argv) {
switch (mcconf->m_sensor_port_mode) {
case SENSOR_PORT_MODE_AS5047_SPI:
commands_printf("SPI encoder value: %d, errors: %d, error rate: %.3f %%",
encoder_cfg_as504x.state.spi_val, encoder_cfg_as504x.state.spi_communication_error_count,
encoder_cfg_as504x.state.spi_val,
encoder_cfg_as504x.state.spi_communication_error_count,
(double)(encoder_cfg_as504x.state.spi_error_rate * 100.0));
if (encoder_cfg_as504x.sw_spi.mosi_gpio != NULL) {
@ -444,12 +521,27 @@ static void terminal_encoder(int argc, const char **argv) {
}
break;
case SENSOR_PORT_MODE_MT6816_SPI:
case SENSOR_PORT_MODE_MT6816_SPI_HW:
commands_printf("Low flux error (no magnet): errors: %d, error rate: %.3f %%",
encoder_cfg_mt6816.state.encoder_no_magnet_error_cnt,
(double)(encoder_cfg_mt6816.state.encoder_no_magnet_error_rate * 100.0));
break;
case SENSOR_PORT_MODE_TLE5014_SSC_HW:
case SENSOR_PORT_MODE_TLE5014_SSC_SW: ;
uint8_t status = encoder_cfg_tle5012.state.last_status_error; // get before other queries
double temperature = 0;
uint16_t magnet_magnitude = 0;
enc_tle5012_get_temperature(&encoder_cfg_tle5012, &temperature);
enc_tle5012_get_magnet_magnitude(&encoder_cfg_tle5012, &magnet_magnitude);
commands_printf("Last error: %d, ssc error rate: %.3f %%, magnet strength: %d, temp %.2f C",
status,
(double)(encoder_cfg_tle5012.state.spi_error_rate * 100.0),
magnet_magnitude,
temperature);
// todo, get/report status word (reg 0x00), make "last error" verbose
break;
case SENSOR_PORT_MODE_TS5700N8501:
case SENSOR_PORT_MODE_TS5700N8501_MULTITURN: {
char sf[9];

View File

@ -23,14 +23,16 @@
#include "hal.h"
#include "encoder_datatype.h"
#include "enc_ts5700n8501.h"
#include "enc_abi.h"
#include "enc_ad2s1205.h"
#include "enc_as5x47u.h"
#include "enc_as504x.h"
#include "enc_bissc.h"
#include "enc_mt6816.h"
#include "enc_sincos.h"
#include "enc_as504x.h"
#include "enc_as5x47u.h"
#include "enc_abi.h"
#include "enc_bissc.h"
#include "enc_tle5012.h"
#include "enc_ts5700n8501.h"
// Functions
bool encoder_init(volatile mc_configuration *conf);

View File

@ -2,11 +2,12 @@ ENCSRC = encoder/encoder.c \
encoder/encoder_cfg.c \
encoder/enc_abi.c \
encoder/enc_ad2s1205.c \
encoder/enc_as504x.c \
encoder/enc_sincos.c \
encoder/enc_mt6816.c \
encoder/enc_ts5700n8501.c \
encoder/enc_as5x47u.c \
encoder/enc_bissc.c
encoder/enc_as504x.c \
encoder/enc_bissc.c \
encoder/enc_mt6816.c \
encoder/enc_sincos.c \
encoder/enc_tle5012.c \
encoder/enc_ts5700n8501.c
ENCINC = encoder

View File

@ -46,6 +46,7 @@ AS504x_config_t encoder_cfg_as504x = {
0, 0,
#endif
HW_HALL_ENC_GPIO2, HW_HALL_ENC_PIN2,
spi_type_sw,
0, // has_started
0, // has_error
{{NULL, NULL}, NULL, NULL} // Mutex
@ -64,6 +65,7 @@ AD2S1205_config_t encoder_cfg_ad2s1205 = {
0, 0,
#endif
HW_HALL_ENC_GPIO2, HW_HALL_ENC_PIN2,
spi_type_sw,
0, // has_started
0, // has_error
{{NULL, NULL}, NULL, NULL} // Mutex
@ -97,6 +99,20 @@ MT6816_config_t encoder_cfg_mt6816 = {
#endif
};
TLE5012_config_t encoder_cfg_tle5012 = {
{
HW_HALL_ENC_GPIO3, HW_HALL_ENC_PIN3, // nss
HW_HALL_ENC_GPIO1, HW_HALL_ENC_PIN1, // sck
HW_HALL_ENC_GPIO2, HW_HALL_ENC_PIN2, // mosi
HW_HALL_ENC_GPIO2, HW_HALL_ENC_PIN2, // miso
ssc_type_sw,
0, // has_started
0, // has_error
{{NULL, NULL}, NULL, NULL} // Mutex
}, //ssc
{0, 0, 0, 0, 0, 0, 0, 0} // State
};
ABI_config_t encoder_cfg_ABI = {
10000, // counts
HW_HALL_ENC_GPIO1, HW_HALL_ENC_PIN1,

View File

@ -23,13 +23,15 @@
#include "encoder_datatype.h"
// Global encoder configurations
extern AS504x_config_t encoder_cfg_as504x;
extern AD2S1205_config_t encoder_cfg_ad2s1205;
extern MT6816_config_t encoder_cfg_mt6816;
extern ABI_config_t encoder_cfg_ABI;
extern ENCSINCOS_config_t encoder_cfg_sincos;
extern TS5700N8501_config_t encoder_cfg_TS5700N8501;
extern AD2S1205_config_t encoder_cfg_ad2s1205;
extern AS5x47U_config_t encoder_cfg_as5x47u;
extern AS504x_config_t encoder_cfg_as504x;
extern BISSC_config_t encoder_cfg_bissc;
extern MT6816_config_t encoder_cfg_mt6816;
extern ENCSINCOS_config_t encoder_cfg_sincos;
extern TLE5012_config_t encoder_cfg_tle5012;
extern TS5700N8501_config_t encoder_cfg_TS5700N8501;
#endif /* ENCODER_CFG_H_ */

View File

@ -31,6 +31,7 @@ typedef enum {
ENCODER_TYPE_NONE = 0,
ENCODER_TYPE_AS504x,
ENCODER_TYPE_MT6816,
ENCODER_TYPE_TLE5012,
ENCODER_TYPE_AD2S1205_SPI,
ENCODER_TYPE_SINCOS,
ENCODER_TYPE_TS5700N8501,
@ -84,6 +85,31 @@ typedef struct {
MT6816_state state;
} MT6816_config_t;
typedef struct {
float spi_error_rate;
float encoder_no_magnet_error_rate;
uint32_t encoder_no_magnet_error_cnt;
float last_enc_angle;
uint32_t spi_error_cnt;
uint8_t last_status_error;
uint32_t spi_val;
uint32_t last_update_time;
} TLE5012_state;
typedef struct { // sw ssc
spi_bb_state sw_spi;
TLE5012_state state;
} TLE5012_config_t;
typedef enum tle5012_errortypes {
NO_ERROR = 0x00, //!< NO_ERROR = Safety word was OK
SYSTEM_ERROR = 0x01, //!< SYSTEM_ERROR = over/under voltage, VDD negative, GND off, ROM defect, no magnet
INTERFACE_ACCESS_ERROR = 0x02, //!< INTERFACE_ACCESS_ERROR = wrong address or wrong lock
INVALID_ANGLE_ERROR = 0x04, //!< INVALID_ANGLE_ERROR = NO_GMR_A = 1 or NO_GMR_XY = 1
ANGLE_SPEED_ERROR = 0x08, //!< ANGLE_SPEED_ERROR = combined error, angular speed calculation wrong
CRC_ERROR = 0xFF //!< CRC_ERROR = Cyclic Redundancy Check (CRC), which includes the STAT and RESP bits wrong
} tle5012_errortypes;
typedef struct {
volatile bool index_found;
volatile float last_enc_angle;