From 28260c6cfc7e1bf93186e40c6b9fdee8df1b8f86 Mon Sep 17 00:00:00 2001 From: Teslafly <2079881+Teslafly@users.noreply.github.com> Date: Tue, 15 Nov 2022 13:34:30 -0600 Subject: [PATCH 1/2] Add tle5012 encoder using software ssc interface --- confgenerator.h | 2 +- datatypes.h | 6 +- driver/spi_bb.c | 103 +++++++- driver/spi_bb.h | 24 +- encoder/enc_mt6816.h | 2 +- encoder/enc_tle5012.c | 499 +++++++++++++++++++++++++++++++++++++ encoder/enc_tle5012.h | 38 +++ encoder/encoder.c | 102 +++++++- encoder/encoder.h | 12 +- encoder/encoder.mk | 11 +- encoder/encoder_cfg.c | 16 ++ encoder/encoder_cfg.h | 12 +- encoder/encoder_datatype.h | 26 ++ 13 files changed, 823 insertions(+), 30 deletions(-) create mode 100644 encoder/enc_tle5012.c create mode 100644 encoder/enc_tle5012.h diff --git a/confgenerator.h b/confgenerator.h index 49153bbb..03d31102 100644 --- a/confgenerator.h +++ b/confgenerator.h @@ -8,7 +8,7 @@ #include // Constants -#define MCCONF_SIGNATURE 347304876 +#define MCCONF_SIGNATURE 853550701 #define APPCONF_SIGNATURE 486554156 // Functions diff --git a/datatypes.h b/datatypes.h index 8d363a4c..7c32cf60 100644 --- a/datatypes.h +++ b/datatypes.h @@ -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 { diff --git a/driver/spi_bb.c b/driver/spi_bb.c index d716ee98..ef9a77be 100644 --- a/driver/spi_bb.c +++ b/driver/spi_bb.c @@ -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(); } diff --git a/driver/spi_bb.h b/driver/spi_bb.h index bcc588da..5bb88ff4 100644 --- a/driver/spi_bb.h +++ b/driver/spi_bb.h @@ -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); diff --git a/encoder/enc_mt6816.h b/encoder/enc_mt6816.h index fd002a8d..a0bc2396 100644 --- a/encoder/enc_mt6816.h +++ b/encoder/enc_mt6816.h @@ -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); diff --git a/encoder/enc_tle5012.c b/encoder/enc_tle5012.c new file mode 100644 index 00000000..dd21b9df --- /dev/null +++ b/encoder/enc_tle5012.c @@ -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 . + + + 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 +#include + +// 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 interface’s 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 +// }; diff --git a/encoder/enc_tle5012.h b/encoder/enc_tle5012.h new file mode 100644 index 00000000..5e68611d --- /dev/null +++ b/encoder/enc_tle5012.h @@ -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 . + */ + +#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_ */ diff --git a/encoder/encoder.c b/encoder/encoder.c index 0dac0171..a5522663 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -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,11 +383,22 @@ 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) { @@ -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]; diff --git a/encoder/encoder.h b/encoder/encoder.h index 1f9d5071..08ac4ba8 100644 --- a/encoder/encoder.h +++ b/encoder/encoder.h @@ -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); diff --git a/encoder/encoder.mk b/encoder/encoder.mk index 08147545..275c17d4 100644 --- a/encoder/encoder.mk +++ b/encoder/encoder.mk @@ -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 diff --git a/encoder/encoder_cfg.c b/encoder/encoder_cfg.c index 91ccc2a0..d2dade10 100644 --- a/encoder/encoder_cfg.c +++ b/encoder/encoder_cfg.c @@ -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, diff --git a/encoder/encoder_cfg.h b/encoder/encoder_cfg.h index 4bf430eb..4186de19 100644 --- a/encoder/encoder_cfg.h +++ b/encoder/encoder_cfg.h @@ -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_ */ diff --git a/encoder/encoder_datatype.h b/encoder/encoder_datatype.h index 2d98b3f4..9cb563f4 100644 --- a/encoder/encoder_datatype.h +++ b/encoder/encoder_datatype.h @@ -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; From 82d71c91e2feff1e56dfccf5fa10ca68d421d22d Mon Sep 17 00:00:00 2001 From: Teslafly <2079881+Teslafly@users.noreply.github.com> Date: Tue, 15 Nov 2022 13:35:02 -0600 Subject: [PATCH 2/2] supress "Echo off" messages in windows --- Makefile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 39861367..5b6760d8 100644 --- a/Makefile +++ b/Makefile @@ -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= fw - Build firmware for " @echo " fw__clean - Remove firmware for " @echo " fw__flash - Use OpenOCD + SWD/JTAG to write firmware to " - @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):