/*
Copyright 2026 Benjamin Vedder benjamin@vedder.se
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 .
*/
#include "enc_amt22.h"
#include "ch.h"
#include "hal.h"
#include "stm32f4xx_conf.h"
#include "hw.h"
#include "mc_interface.h"
#include "utils_math.h"
#include "spi_bb.h"
#include "timer.h"
#include
#include
// Private functions
static bool verify_checksum(uint16_t message);
bool enc_amt22_init(AMT22_config_t *cfg) {
memset(&cfg->state, 0, sizeof(AS504x_state));
spi_bb_init(&(cfg->sw_spi));
return true;
}
void enc_amt22_deinit(AMT22_config_t *cfg) {
spi_bb_deinit(&(cfg->sw_spi));
cfg->state.last_enc_angle = 0.0;
cfg->state.spi_error_rate = 0.0;
}
void enc_amt22_routine(AMT22_config_t *cfg) {
uint16_t pos;
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();
spi_bb_begin(&(cfg->sw_spi));
// Use two 8-bit transfers to respect TB
uint16_t b0 = spi_bb_exchange_8(&(cfg->sw_spi), 0x00);
spi_bb_delay();
spi_bb_delay();
uint16_t b1 = spi_bb_exchange_8(&(cfg->sw_spi), 0x00);
spi_bb_end(&(cfg->sw_spi));
pos = b0 << 8 | b1;
cfg->state.spi_val = pos;
if (verify_checksum(pos)) {
pos &= 0x3FFF;
cfg->state.last_enc_angle = ((float) pos * 360.0) / 16384.0;
UTILS_LP_FAST(cfg->state.spi_error_rate, 0.0, timestep);
} else {
++cfg->state.spi_error_cnt;
UTILS_LP_FAST(cfg->state.spi_error_rate, 1.0, timestep);
}
}
float enc_amt22_read_angle(AMT22_config_t *cfg) {
enc_amt22_routine(cfg);
return cfg->state.last_enc_angle;
}
static bool verify_checksum(uint16_t message) {
uint16_t checksum = 0x3;
for (int i = 0; i < 14; i += 2) {
checksum ^= (message >> i) & 0x3;
}
return checksum == (message >> 14);
}