sysctl: implement more spi and serial reporting functionality
This commit is contained in:
parent
638b536ce0
commit
d12064b469
|
@ -1,4 +1,5 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "pico/binary_info.h"
|
||||
#include "pico/sleep.h"
|
||||
|
@ -9,7 +10,10 @@
|
|||
#include "fusb302b.h"
|
||||
#include "pd.h"
|
||||
|
||||
#define FW_REV "PREF1SYS D2 20231207"
|
||||
#define FW_STRING1 "PREF1SYS"
|
||||
#define FW_STRING2 "R1"
|
||||
#define FW_STRING3 "20240410"
|
||||
#define FW_REV FW_STRING1 FW_STRING2 FW_STRING3
|
||||
|
||||
#define PIN_SDA 0
|
||||
#define PIN_SCL 1
|
||||
|
@ -58,6 +62,20 @@
|
|||
#define STOP_BITS 1
|
||||
#define PARITY UART_PARITY_NONE
|
||||
|
||||
// battery information
|
||||
// TODO: turn into a struct
|
||||
// 4.8A x 3600 seconds/hour (per cell)
|
||||
#define MAX_CAPACITY (4.0)*3600.0
|
||||
float report_capacity_max_ampsecs = MAX_CAPACITY;
|
||||
float report_capacity_accu_ampsecs = MAX_CAPACITY;
|
||||
float report_capacity_min_ampsecs = 0;
|
||||
int report_capacity_percentage = 0;
|
||||
float report_volts = 0;
|
||||
float report_current = 0;
|
||||
float report_cells_v[8] = {0,0,0,0,0,0,0,0};
|
||||
bool reached_full_charge = true; // FIXME
|
||||
bool som_is_powered = false;
|
||||
bool print_pack_info = false;
|
||||
|
||||
void i2c_scan() {
|
||||
printf("\nI2C Scan\n");
|
||||
|
@ -451,10 +469,14 @@ float charger_dump() {
|
|||
uint8_t precharge_c = mps_read_byte(0x03);
|
||||
uint8_t bat_full_v = mps_read_byte(0x04);
|
||||
|
||||
int print_charger_info = 1;
|
||||
if (print_charger_info) {
|
||||
// carry over to globals for SPI reporting
|
||||
report_current = -(adc_input_c - adc_discharge_c);
|
||||
report_volts = adc_sys_v;
|
||||
|
||||
if (print_pack_info) {
|
||||
printf("[charger info]\n");
|
||||
printf(" status: %x\n", status);
|
||||
printf(" reported current: %f voltage: %f\n", report_current, report_volts);
|
||||
printf(" fault: %x\n ------------\n", fault);
|
||||
|
||||
printf(" adc_bat_v: %f\n", adc_bat_v);
|
||||
|
@ -525,21 +547,29 @@ void max_dump() {
|
|||
float rep_time_to_empty = max_word_to_time(max_read_word(0x11));
|
||||
float rep_time_to_full = max_word_to_time(max_read_word(0x20));
|
||||
|
||||
// carry over to globals
|
||||
report_capacity_percentage = (int)rep_percentage;
|
||||
// charger mostly doesn't charge to >98%
|
||||
if (report_capacity_percentage >= 98) report_capacity_percentage = 100;
|
||||
report_cells_v[0] = cell1;
|
||||
report_cells_v[1] = cell2;
|
||||
|
||||
if (print_pack_info) {
|
||||
printf("[pack info]\n");
|
||||
|
||||
printf(" comm_stat: %04x\n", comm_stat);
|
||||
|
||||
printf(" packcfg: %04x\n", packcfg);
|
||||
printf(" status: %04x\n", status);
|
||||
if (status & 0x8000) {
|
||||
printf(" `-- prot alert\n");
|
||||
}
|
||||
}
|
||||
if (status & 0x0002) {
|
||||
printf(" `-- POR, clearing\n");
|
||||
max_write_word(0x61, 0x0000);
|
||||
max_write_word(0x61, 0x0000);
|
||||
max_write_word(0x00, status & (~0x0002));
|
||||
}
|
||||
if (print_pack_info) {
|
||||
printf(" prot_alert: %04x\n", prot_alert);
|
||||
printf(" prot_cfg2: %04x\n", prot_cfg2);
|
||||
printf(" therm_cfg: %04x\n", therm_cfg);
|
||||
|
@ -612,6 +642,7 @@ void max_dump() {
|
|||
printf(" rep_time_to_empty: %f s\n", rep_time_to_empty);
|
||||
printf(" rep_time_to_full: %f s\n", rep_time_to_full);
|
||||
printf(" ============\n");
|
||||
}
|
||||
|
||||
char report[128];
|
||||
sprintf(report, "%04d %05d %05d %06d %06d\r\n",
|
||||
|
@ -623,8 +654,8 @@ void max_dump() {
|
|||
|
||||
uart_puts(UART_ID, report);
|
||||
|
||||
printf(" report: %s", report);
|
||||
printf(" ============\n");
|
||||
//printf(" report: %s", report);
|
||||
//printf(" ============\n");
|
||||
}
|
||||
|
||||
void turn_som_power_on() {
|
||||
|
@ -663,6 +694,8 @@ void turn_som_power_on() {
|
|||
|
||||
// done with latching
|
||||
gpio_put(PIN_PWREN_LATCH, 0);
|
||||
|
||||
som_is_powered = true;
|
||||
}
|
||||
|
||||
void turn_som_power_off() {
|
||||
|
@ -695,6 +728,8 @@ void turn_som_power_off() {
|
|||
|
||||
// done with latching
|
||||
gpio_put(PIN_PWREN_LATCH, 0);
|
||||
|
||||
som_is_powered = false;
|
||||
}
|
||||
|
||||
void som_wake() {
|
||||
|
@ -708,6 +743,7 @@ void som_wake() {
|
|||
#define ST_EXPECT_CMD 4
|
||||
#define ST_SYNTAX_ERROR 5
|
||||
#define ST_EXPECT_RETURN 6
|
||||
#define ST_EXPECT_MAGIC 7
|
||||
|
||||
char remote_cmd = 0;
|
||||
uint8_t remote_arg = 0;
|
||||
|
@ -819,7 +855,7 @@ void handle_commands(char chr) {
|
|||
}
|
||||
else if (remote_cmd == 's') {
|
||||
// TODO
|
||||
sprintf(uart_buffer,FW_REV"normal,%d,%d,%d\r",0,0,0);
|
||||
sprintf(uart_buffer,FW_REV"normal,%d,%d,%d\r\n",0,0,0);
|
||||
uart_puts(UART_ID, uart_buffer);
|
||||
}
|
||||
else if (remote_cmd == 'u') {
|
||||
|
@ -836,7 +872,30 @@ void handle_commands(char chr) {
|
|||
else if (remote_cmd == 'c') {
|
||||
// TODO
|
||||
// get status of cells, current, voltage, fuel gauge
|
||||
sprintf(uart_buffer, "%d\r\n", 0);
|
||||
int mA = (int)(report_current*1000.0);
|
||||
char mA_sign = ' ';
|
||||
if (mA<0) {
|
||||
mA = -mA;
|
||||
mA_sign = '-';
|
||||
}
|
||||
int mV = (int)(report_volts*1000.0);
|
||||
sprintf(uart_buffer,"%02d %02d %02d %02d %02d %02d %02d %02d mA%c%04dmV%05d %3d%% P%d\r\n",
|
||||
(int)(report_cells_v[0]/100),
|
||||
(int)(report_cells_v[1]/100),
|
||||
(int)(report_cells_v[2]/100),
|
||||
(int)(report_cells_v[3]/100),
|
||||
(int)(report_cells_v[4]/100),
|
||||
(int)(report_cells_v[5]/100),
|
||||
(int)(report_cells_v[6]/100),
|
||||
(int)(report_cells_v[7]/100),
|
||||
mA_sign,
|
||||
mA,
|
||||
mV,
|
||||
report_capacity_percentage,
|
||||
som_is_powered?1:0);
|
||||
|
||||
printf("[gauge] [%s]\n", uart_buffer);
|
||||
|
||||
uart_puts(UART_ID, uart_buffer);
|
||||
}
|
||||
else if (remote_cmd == 'S') {
|
||||
|
@ -868,27 +927,196 @@ void handle_commands(char chr) {
|
|||
}
|
||||
}
|
||||
|
||||
void on_uart_rx() {
|
||||
while (uart_is_readable(UART_ID)) {
|
||||
handle_commands(uart_getc(UART_ID));
|
||||
}
|
||||
}
|
||||
#define SPI_BUF_LEN 0x8
|
||||
uint8_t spi_buf[SPI_BUF_LEN];
|
||||
unsigned char spi_cmd_state = ST_EXPECT_MAGIC;
|
||||
unsigned char spi_command = '\0';
|
||||
uint8_t spi_arg1 = 0;
|
||||
|
||||
#define SPI_BUF_LEN 0x100
|
||||
uint8_t spi_out_buf[SPI_BUF_LEN];
|
||||
uint8_t spi_in_buf[SPI_BUF_LEN];
|
||||
void init_spi_client() {
|
||||
spi_init(spi1, 1000 * 1000);
|
||||
// we don't appreciate the wording, but it's the API we are given
|
||||
spi_set_slave(spi1, true);
|
||||
gpio_set_function(PIN_SOM_MOSI, GPIO_FUNC_SPI);
|
||||
gpio_set_function(PIN_SOM_MISO, GPIO_FUNC_SPI);
|
||||
gpio_set_function(PIN_SOM_SS0, GPIO_FUNC_SPI);
|
||||
gpio_set_function(PIN_SOM_SCK, GPIO_FUNC_SPI);
|
||||
|
||||
spi_init(spi1, 400 * 1000);
|
||||
// we don't appreciate the wording, but it's the API we are given
|
||||
spi_set_slave(spi1, true);
|
||||
spi_set_format(spi1, 8, SPI_CPOL_0, SPI_CPHA_1, SPI_MSB_FIRST);
|
||||
|
||||
printf("[init_spi_client] done.\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SPI command from imx poll function
|
||||
*
|
||||
* Ported from MNT Reform reform2-lpc-fw.
|
||||
*/
|
||||
void handle_spi_commands() {
|
||||
int len = 0;
|
||||
int all_zeroes = 1;
|
||||
|
||||
while (spi_is_readable(spi1) && len < SPI_BUF_LEN) {
|
||||
// 0x00 is some "repeated tx data"
|
||||
spi_read_blocking(spi1, 0x00, &spi_buf[len], 1);
|
||||
if (spi_buf[len] != 0) all_zeroes = 0;
|
||||
len++;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
printf("[spi] rx len: %d, %02x %02x %02x %02x %02x %02x %02x %02x\n", len, spi_buf[0], spi_buf[1], spi_buf[2], spi_buf[3], spi_buf[4], spi_buf[5], spi_buf[6], spi_buf[7]);
|
||||
|
||||
// states:
|
||||
// 0 arg1 byte expected
|
||||
// 4 command byte expected
|
||||
// 6 execute command
|
||||
// 7 magic byte expected
|
||||
for (uint8_t s = 0; s < len; s++) {
|
||||
if (spi_cmd_state == ST_EXPECT_MAGIC) {
|
||||
// magic byte found, prevents garbage data
|
||||
// in the bus from triggering a command
|
||||
if (spi_buf[s] == 0xB5) {
|
||||
spi_cmd_state = ST_EXPECT_CMD;
|
||||
}
|
||||
}
|
||||
else if (spi_cmd_state == ST_EXPECT_CMD) {
|
||||
// read command
|
||||
spi_command = spi_buf[s];
|
||||
spi_cmd_state = ST_EXPECT_DIGIT_0;
|
||||
}
|
||||
else if (spi_cmd_state == ST_EXPECT_DIGIT_0) {
|
||||
// read arg1 byte
|
||||
spi_arg1 = spi_buf[s];
|
||||
spi_cmd_state = ST_EXPECT_RETURN;
|
||||
}
|
||||
}
|
||||
|
||||
if (spi_cmd_state == ST_EXPECT_MAGIC && !all_zeroes) {
|
||||
// reset SPI0 block
|
||||
// this is a workaround for confusion with
|
||||
// software spi from BPI-CM4 where we get
|
||||
// bit-shifted bytes
|
||||
|
||||
// FIXME
|
||||
init_spi_client();
|
||||
}
|
||||
|
||||
if (spi_cmd_state != ST_EXPECT_RETURN) {
|
||||
// waiting for more data
|
||||
return;
|
||||
}
|
||||
|
||||
printf("[spi] exec:%c,%02x\r\n", spi_command, spi_arg1);
|
||||
|
||||
// clear receive buffer, reuse as send buffer
|
||||
memset(spi_buf, 0, SPI_BUF_LEN);
|
||||
|
||||
// execute power state command
|
||||
if (spi_command == 'p') {
|
||||
// toggle system power and/or reset imx
|
||||
if (spi_arg1 == 1) {
|
||||
turn_som_power_off();
|
||||
init_spi_client();
|
||||
return;
|
||||
}
|
||||
if (spi_arg1 == 2) {
|
||||
turn_som_power_on();
|
||||
init_spi_client();
|
||||
return;
|
||||
}
|
||||
if (spi_arg1 == 3) {
|
||||
// TODO
|
||||
//reset_som();
|
||||
}
|
||||
|
||||
spi_buf[0] = som_is_powered;
|
||||
}
|
||||
// return firmware version and api info
|
||||
else if (spi_command == 'f') {
|
||||
if(spi_arg1 == 0) {
|
||||
memcpy(spi_buf, FW_STRING1, 8);
|
||||
}
|
||||
else if(spi_arg1 == 1) {
|
||||
memcpy(spi_buf, FW_STRING2, 2);
|
||||
}
|
||||
else {
|
||||
memcpy(spi_buf, FW_STRING3, 8);
|
||||
}
|
||||
}
|
||||
// execute status query command
|
||||
else if (spi_command == 'q') {
|
||||
uint8_t percentage = (uint8_t)report_capacity_percentage;
|
||||
int16_t voltsInt = (int16_t)(report_volts*1000.0);
|
||||
int16_t currentInt = (int16_t)(report_current*1000.0);
|
||||
|
||||
spi_buf[0] = (uint8_t)voltsInt;
|
||||
spi_buf[1] = (uint8_t)(voltsInt >> 8);
|
||||
spi_buf[2] = (uint8_t)currentInt;
|
||||
spi_buf[3] = (uint8_t)(currentInt >> 8);
|
||||
spi_buf[4] = (uint8_t)percentage;
|
||||
spi_buf[5] = (uint8_t)0; // TODO "state" not implemented
|
||||
spi_buf[6] = (uint8_t)0;
|
||||
}
|
||||
// get cell voltage
|
||||
else if (spi_command == 'v') {
|
||||
uint16_t volts = 0;
|
||||
uint8_t cell1 = 0;
|
||||
|
||||
if (spi_arg1 == 1) {
|
||||
cell1 = 4;
|
||||
}
|
||||
|
||||
for (uint8_t c = 0; c < 4; c++) {
|
||||
volts = report_cells_v[c + cell1];
|
||||
spi_buf[c*2] = (uint8_t)volts;
|
||||
spi_buf[(c*2)+1] = (uint8_t)(volts >> 8);
|
||||
}
|
||||
}
|
||||
// get calculated capacity
|
||||
else if (spi_command == 'c') {
|
||||
uint16_t cap_accu = (uint16_t) report_capacity_max_ampsecs / 3.6;
|
||||
uint16_t cap_min = (uint16_t) report_capacity_min_ampsecs / 3.6;
|
||||
uint16_t cap_max = (uint16_t) report_capacity_max_ampsecs / 3.6;
|
||||
|
||||
spi_buf[0] = (uint8_t)cap_accu;
|
||||
spi_buf[1] = (uint8_t)(cap_accu >> 8);
|
||||
spi_buf[2] = (uint8_t)cap_min;
|
||||
spi_buf[3] = (uint8_t)(cap_min >> 8);
|
||||
spi_buf[4] = (uint8_t)cap_max;
|
||||
spi_buf[5] = (uint8_t)(cap_max >> 8);
|
||||
}
|
||||
else if (spi_command == 'u') {
|
||||
// not implemented
|
||||
}
|
||||
|
||||
// FIXME: if we don't reset, SPI wants to transact the amount of bytes
|
||||
// that we read above for unknown reasons
|
||||
init_spi_client();
|
||||
|
||||
spi_write_blocking(spi1, spi_buf, SPI_BUF_LEN);
|
||||
|
||||
// clear any pending reads
|
||||
/*while (spi_is_readable(spi1)) {
|
||||
printf("[spi] clearing rx...\n");
|
||||
spi_read_blocking(spi1, 0x00, &spi_buf[0], 1);
|
||||
}*/
|
||||
|
||||
spi_cmd_state = ST_EXPECT_MAGIC;
|
||||
spi_command = 0;
|
||||
spi_arg1 = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void on_uart_rx() {
|
||||
while (uart_is_readable(UART_ID)) {
|
||||
handle_commands(uart_getc(UART_ID));
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
//set_sys_clock_48mhz();
|
||||
|
||||
|
@ -987,9 +1215,11 @@ int main() {
|
|||
gpio_set_dir(PIN_USB_SRC_ENABLE, 1);
|
||||
gpio_put(PIN_USB_SRC_ENABLE, 0);
|
||||
|
||||
turn_som_power_on();
|
||||
|
||||
// latch the PWR and display pins
|
||||
gpio_put(PIN_PWREN_LATCH, 1);
|
||||
gpio_put(PIN_PWREN_LATCH, 0);
|
||||
//gpio_put(PIN_PWREN_LATCH, 1);
|
||||
//gpio_put(PIN_PWREN_LATCH, 0);
|
||||
|
||||
unsigned int t = 0;
|
||||
unsigned int t_report = 0;
|
||||
|
@ -1016,11 +1246,7 @@ int main() {
|
|||
handle_commands(uart_getc(UART_ID));
|
||||
}
|
||||
|
||||
while (spi_is_readable(spi1)) {
|
||||
// 0x01 is some "repeated tx data"
|
||||
spi_read_blocking(spi1, 0x01, spi_in_buf, 1);
|
||||
printf("[spi read] %02x\n", spi_in_buf[0]);
|
||||
}
|
||||
handle_spi_commands();
|
||||
|
||||
// handle commands over usb serial
|
||||
int usb_c = getchar_timeout_us(0);
|
||||
|
@ -1032,6 +1258,9 @@ int main() {
|
|||
else if (usb_c == '0') {
|
||||
turn_som_power_off();
|
||||
}
|
||||
else if (usb_c == 'p') {
|
||||
print_pack_info = !print_pack_info;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == 0) {
|
||||
|
|
Loading…
Reference in New Issue