bldc/hwconf/drv8323s.c

476 lines
11 KiB
C
Raw Normal View History

2018-03-18 04:12:04 -07:00
/*
Copyright 2016 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 <http://www.gnu.org/licenses/>.
*/
2018-03-18 04:12:04 -07:00
#include "hw.h"
2019-02-18 10:30:19 -08:00
#ifdef HW_HAS_DRV8323S
2018-03-18 04:12:04 -07:00
2019-02-18 10:30:19 -08:00
#include "drv8323s.h"
2018-03-18 04:12:04 -07:00
#include "ch.h"
#include "hal.h"
#include "stm32f4xx_conf.h"
#include "utils.h"
#include "terminal.h"
#include "commands.h"
2018-03-18 04:12:04 -07:00
#include <string.h>
#include <stdio.h>
2018-03-18 04:12:04 -07:00
// Private functions
static uint16_t spi_exchange(uint16_t x);
static void spi_transfer(uint16_t *in_buf, const uint16_t *out_buf, int length);
static void spi_begin(void);
static void spi_end(void);
static void spi_delay(void);
static void terminal_read_reg(int argc, const char **argv);
static void terminal_write_reg(int argc, const char **argv);
static void terminal_set_oc_adj(int argc, const char **argv);
static void terminal_print_faults(int argc, const char **argv);
static void terminal_reset_faults(int argc, const char **argv);
2018-03-18 04:12:04 -07:00
// Private variables
static char m_fault_print_buffer[120];
2019-02-18 10:30:19 -08:00
void drv8323s_init(void) {
// DRV8323S SPI
palSetPadMode(DRV8323S_MISO_GPIO, DRV8323S_MISO_PIN, PAL_MODE_INPUT_PULLUP);
palSetPadMode(DRV8323S_SCK_GPIO, DRV8323S_SCK_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
palSetPadMode(DRV8323S_CS_GPIO, DRV8323S_CS_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
palSetPadMode(DRV8323S_MOSI_GPIO, DRV8323S_MOSI_PIN, PAL_MODE_OUTPUT_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
palSetPad(DRV8323S_MOSI_GPIO, DRV8323S_MOSI_PIN);
2018-03-18 04:12:04 -07:00
chThdSleepMilliseconds(100);
// Disable OC 0000TTDDMMOOVVVV
drv8323s_write_reg(5, 0b0000000111010000);
2019-02-18 10:30:19 -08:00
// Set shunt amp gain
drv8323s_set_current_amp_gain(CURRENT_AMP_GAIN);
terminal_register_command_callback(
2019-02-18 10:30:19 -08:00
"drv8323s_read_reg",
"Read a register from the DRV8323S and print it.",
"[reg]",
terminal_read_reg);
terminal_register_command_callback(
2019-02-18 10:30:19 -08:00
"drv8323s_write_reg",
"Write to a DRV8323S register.",
"[reg] [hexvalue]",
terminal_write_reg);
terminal_register_command_callback(
2019-02-18 10:30:19 -08:00
"drv8323s_set_oc_adj",
"Set the DRV8323S OC ADJ register.",
"[value]",
terminal_set_oc_adj);
terminal_register_command_callback(
2019-02-18 10:30:19 -08:00
"drv8323s_print_faults",
"Print all current DRV8323S faults.",
0,
terminal_print_faults);
terminal_register_command_callback(
2019-02-18 10:30:19 -08:00
"drv8323s_reset_faults",
"Reset all latched DRV8323S faults.",
0,
terminal_reset_faults);
2018-03-18 04:12:04 -07:00
}
/**
2019-02-18 10:30:19 -08:00
* Set the threshold of the over current protection of the DRV8323S. It works by measuring
2018-03-18 04:12:04 -07:00
* the voltage drop across drain-source of the MOSFETs and activates when it is higher than
* a set value. Notice that this current limit is not very accurate.
*
* @param val
* The value to use. Range [0 15]. A lower value corresponds to a lower current limit. See
2019-02-18 10:30:19 -08:00
* the drv8323s datasheet for how to convert these values to currents.
2018-03-18 04:12:04 -07:00
*/
2019-02-18 10:30:19 -08:00
void drv8323s_set_oc_adj(int val) {
// Match with the drv8301 levels
val >>= 1;
2019-02-18 10:30:19 -08:00
int reg = drv8323s_read_reg(5);
reg &= 0xFFF0;
2018-03-18 04:12:04 -07:00
reg |= (val & 0xF);
2019-02-18 10:30:19 -08:00
drv8323s_write_reg(5, reg);
2018-03-18 04:12:04 -07:00
}
/**
2019-02-18 10:30:19 -08:00
* Set the gain of the shunt amps DRV8323S.
2018-03-18 04:12:04 -07:00
*
* @param mode
*/
2019-02-18 10:30:19 -08:00
void drv8323s_set_oc_mode(drv8301_oc_mode mode) {
// Match with the drv8301 modes
if (mode == DRV8301_OC_LATCH_SHUTDOWN) {
mode = DRV8301_OC_LIMIT;
} else if (mode == DRV8301_OC_LIMIT) {
mode = DRV8301_OC_LATCH_SHUTDOWN;
}
2019-02-18 10:30:19 -08:00
int reg = drv8323s_read_reg(5);
2018-03-18 04:12:04 -07:00
reg &= 0xFF3F;
reg |= (mode & 0x03) << 6;
2019-02-18 10:30:19 -08:00
drv8323s_write_reg(5, reg);
}
/**
* Set the gain of the DRV8323S.
*
* @param gain
* The gain of the shunt amps.
*/
void drv8323s_set_current_amp_gain(int gain) {
int reg = drv8323s_read_reg(6);
reg &= ~(0x03 << 6);
switch(gain) {
case 5:
reg |= (0 & 0x03) << 6;
break;
case 10:
reg |= (1 & 0x03) << 6;
break;
case 20:
reg |= (2 & 0x03) << 6;
break;
case 40:
reg |= (3 & 0x03) << 6;
break;
default:
//gain not supported
break;
}
drv8323s_write_reg(6, reg);
}
void drv8323s_dccal_on(void)
{
int reg = drv8323s_read_reg(6);
reg |= (1 << 2);
drv8323s_write_reg(6, reg);
}
void drv8323s_dccal_off(void)
{
int reg = drv8323s_read_reg(6);
reg &= ~(1 << 2);
drv8323s_write_reg(6, reg);
2018-03-18 04:12:04 -07:00
}
/**
2019-02-18 10:30:19 -08:00
* Read the fault codes of the DRV8323S.
2018-03-18 04:12:04 -07:00
*
* @return
* The fault codes, where the bits represent the following:
* b0: FETLC_OC
* b1: FETHC_OC
* b2: FETLB_OC
* b3: FETHB_OC
* b4: FETLA_OC
* b5: FETHA_OC
* b6: OTW
* b7: OTSD
* b8: PVDD_UV
* b9: GVDD_UV
* b10: FAULT
* b11: GVDD_OV
*
*/
2019-02-18 10:30:19 -08:00
unsigned long drv8323s_read_faults(void) {
unsigned long r0 = drv8323s_read_reg(0);
int r1 = drv8323s_read_reg(1);
2018-03-18 04:12:04 -07:00
return r0 | (r1 << 16);
}
/**
* Reset all latched faults.
*/
2019-02-18 10:30:19 -08:00
void drv8323s_reset_faults(void) {
int reg = drv8323s_read_reg(2);
2018-03-18 04:12:04 -07:00
reg |= 1;
2019-02-18 10:30:19 -08:00
drv8323s_write_reg(2, reg);
2018-03-18 04:12:04 -07:00
}
2019-02-18 10:30:19 -08:00
char* drv8323s_faults_to_string(unsigned long faults) {
2018-03-18 04:12:04 -07:00
if (faults == 0) {
2019-02-18 10:30:19 -08:00
strcpy(m_fault_print_buffer, "No DRV8323S faults");
2018-03-18 04:12:04 -07:00
} else {
strcpy(m_fault_print_buffer, "|");
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_FET_LC_OC) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " FETLC_OC |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_FET_HC_OC) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " FETHC_OC |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_FET_LB_OC) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " FETLB_OC |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_FET_HB_OC) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " FETHB_OC |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_FET_LA_OC) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " FETLA_OC |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_FET_HA_OC) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " FETHA_OC |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_OTSD) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " OTSD |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_UVLO) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " UVLO |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_GDF) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " GDF |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_VDS_OCP) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " VDS OCP |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_FAULT) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " FAULT |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_VGS_LC) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " FETLC VGS |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_VGS_HC) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " FETHC VGS |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_VGS_LB) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " FETLB VGS |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_VGS_HB) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " FETHB VGS |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_VGS_LA) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " FETLA VGS |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_VGS_HA) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " FETHA VGS |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_CPUV) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " CPU V |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_OTW) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " OTW |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_SC_OC) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " AMP C OC |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_SB_OC) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " AMP B OC |");
}
2019-02-18 10:30:19 -08:00
if (faults & DRV8323S_FAULT_SA_OC) {
2018-03-18 04:12:04 -07:00
strcat(m_fault_print_buffer, " AMP A OC |");
}
}
return m_fault_print_buffer;
}
2019-02-18 10:30:19 -08:00
unsigned int drv8323s_read_reg(int reg) {
2018-03-18 04:12:04 -07:00
uint16_t out = 0;
out |= (1 << 15);
out |= (reg & 0x0F) << 11;
out |= 0x807F;
if (reg != 0) {
spi_begin();
spi_exchange(out);
spi_end();
}
spi_begin();
uint16_t res = spi_exchange(out);
spi_end();
return res;
}
2019-02-18 10:30:19 -08:00
void drv8323s_write_reg(int reg, int data) {
2018-03-18 04:12:04 -07:00
uint16_t out = 0;
out |= (reg & 0x0F) << 11;
out |= data & 0x7FF;
spi_begin();
spi_exchange(out);
spi_end();
}
// Software SPI
static uint16_t spi_exchange(uint16_t x) {
uint16_t rx;
spi_transfer(&rx, &x, 1);
return rx;
}
static void spi_transfer(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;
for (int bit = 0;bit < 16;bit++) {
2019-02-18 10:30:19 -08:00
palWritePad(DRV8323S_MOSI_GPIO, DRV8323S_MOSI_PIN, send >> 15);
2018-03-18 04:12:04 -07:00
send <<= 1;
2019-02-18 10:30:19 -08:00
palSetPad(DRV8323S_SCK_GPIO, DRV8323S_SCK_PIN);
2018-03-18 04:12:04 -07:00
spi_delay();
2019-02-18 10:30:19 -08:00
palClearPad(DRV8323S_SCK_GPIO, DRV8323S_SCK_PIN);
2018-03-18 04:12:04 -07:00
int r1, r2, r3;
2019-02-18 10:30:19 -08:00
r1 = palReadPad(DRV8323S_MISO_GPIO, DRV8323S_MISO_PIN);
2018-03-18 04:12:04 -07:00
__NOP();
2019-02-18 10:30:19 -08:00
r2 = palReadPad(DRV8323S_MISO_GPIO, DRV8323S_MISO_PIN);
2018-03-18 04:12:04 -07:00
__NOP();
2019-02-18 10:30:19 -08:00
r3 = palReadPad(DRV8323S_MISO_GPIO, DRV8323S_MISO_PIN);
2018-03-18 04:12:04 -07:00
receive <<= 1;
if (utils_middle_of_3_int(r1, r2, r3)) {
receive |= 1;
}
spi_delay();
}
if (in_buf) {
in_buf[i] = receive;
}
}
}
static void spi_begin(void) {
2019-02-18 10:30:19 -08:00
palClearPad(DRV8323S_CS_GPIO, DRV8323S_CS_PIN);
2018-03-18 04:12:04 -07:00
}
static void spi_end(void) {
2019-02-18 10:30:19 -08:00
palSetPad(DRV8323S_CS_GPIO, DRV8323S_CS_PIN);
2018-03-18 04:12:04 -07:00
}
static void spi_delay(void) {
for (volatile int i = 0;i < 10;i++) {
__NOP();
}
}
static void terminal_read_reg(int argc, const char **argv) {
if (argc == 2) {
int reg = -1;
sscanf(argv[1], "%d", &reg);
if (reg >= 0) {
2019-02-18 10:30:19 -08:00
unsigned int res = drv8323s_read_reg(reg);
char bl[9];
char bh[9];
utils_byte_to_binary((res >> 8) & 0xFF, bh);
utils_byte_to_binary(res & 0xFF, bl);
commands_printf("Reg 0x%02x: %s %s (0x%04x)\n", reg, bh, bl, res);
} else {
commands_printf("Invalid argument(s).\n");
}
} else {
commands_printf("This command requires one argument.\n");
}
}
static void terminal_write_reg(int argc, const char **argv) {
if (argc == 3) {
int reg = -1;
int val = -1;
sscanf(argv[1], "%d", &reg);
sscanf(argv[2], "%x", &val);
if (reg >= 0 && val >= 0) {
2019-02-18 10:30:19 -08:00
drv8323s_write_reg(reg, val);
unsigned int res = drv8323s_read_reg(reg);
char bl[9];
char bh[9];
utils_byte_to_binary((res >> 8) & 0xFF, bh);
utils_byte_to_binary(res & 0xFF, bl);
commands_printf("New reg value 0x%02x: %s %s (0x%04x)\n", reg, bh, bl, res);
} else {
commands_printf("Invalid argument(s).\n");
}
} else {
commands_printf("This command requires two arguments.\n");
}
}
static void terminal_set_oc_adj(int argc, const char **argv) {
if (argc == 2) {
int val = -1;
sscanf(argv[1], "%d", &val);
if (val >= 0 && val < 32) {
2019-02-18 10:30:19 -08:00
drv8323s_set_oc_adj(val);
unsigned int res = drv8323s_read_reg(5);
char bl[9];
char bh[9];
utils_byte_to_binary((res >> 8) & 0xFF, bh);
utils_byte_to_binary(res & 0xFF, bl);
commands_printf("New reg value 0x%02x: %s %s (0x%04x)\n", 2, bh, bl, res);
} else {
commands_printf("Invalid argument(s).\n");
}
} else {
commands_printf("This command requires one argument.\n");
}
}
static void terminal_print_faults(int argc, const char **argv) {
(void)argc;
(void)argv;
2019-02-18 10:30:19 -08:00
commands_printf(drv8323s_faults_to_string(drv8323s_read_faults()));
}
static void terminal_reset_faults(int argc, const char **argv) {
(void)argc;
(void)argv;
2019-02-18 10:30:19 -08:00
drv8323s_reset_faults();
}
2018-03-18 04:12:04 -07:00
#endif