mirror of
https://gitlab.com/hyperglitch/jellyfish.git
synced 2025-12-26 15:16:30 +00:00
353 lines
10 KiB
C
353 lines
10 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2025 Igor Brkic <igor@hyperglitch.com>
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "cmsis_os.h"
|
|
|
|
#include "../lib/ST7789/st7789.h"
|
|
#include "../images/splash.h"
|
|
|
|
#include "jf_common.h"
|
|
#include "jf_ui.h"
|
|
|
|
#include "aux_power.h"
|
|
#include "jf_adc.h"
|
|
#include "jf_measure.h"
|
|
#include "jf_qspi.h"
|
|
#include "jf_routing.h"
|
|
#include "jf_source.h"
|
|
|
|
#include "main.h"
|
|
#include "stm32f4xx_it.h"
|
|
|
|
extern TIM_HandleTypeDef htim4; // LED PWM timer
|
|
|
|
static jf_ui_t user_input_state = {0};
|
|
|
|
typedef enum {
|
|
//LED_BLINK,
|
|
//ADC_GET,
|
|
DAC_SET,
|
|
ISET_DAC,
|
|
EXTIN,
|
|
//RANGE,
|
|
VAUX_SET,
|
|
UI_FUNC_COUNT
|
|
} ui_function_t;
|
|
|
|
const char ui_func_labels[UI_FUNC_COUNT][13] = {
|
|
//"LED ",
|
|
//"ADC_GET",
|
|
"VOUT ",
|
|
"ILIM ",
|
|
"EXTIN ",
|
|
//"RANGE ",
|
|
"AUX SET",
|
|
};
|
|
|
|
|
|
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
|
|
static uint32_t last_change = 0;
|
|
static uint32_t enc_state_last_change = 0;
|
|
static int32_t state_last = 0;
|
|
const uint32_t enc_debounce_ms = 10;
|
|
|
|
switch(GPIO_Pin){
|
|
case BUTTON_Pin:
|
|
const uint32_t btn = HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin);
|
|
if(btn!=user_input_state.btn){
|
|
user_input_state.btn = btn;
|
|
user_input_state.btn_evt_id++;
|
|
}
|
|
return;
|
|
case ENCODER_SW_Pin:
|
|
const uint32_t enc_sw = HAL_GPIO_ReadPin(ENCODER_SW_GPIO_Port, ENCODER_SW_Pin);
|
|
if(enc_sw!=user_input_state.enc_sw){
|
|
user_input_state.enc_sw = enc_sw;
|
|
user_input_state.enc_sw_evt_id++;
|
|
}
|
|
return;
|
|
default: ;
|
|
}
|
|
|
|
if(GPIO_Pin!=ENCODER_A_Pin && GPIO_Pin!=ENCODER_B_Pin) return;
|
|
|
|
const uint32_t tm = HAL_GetTick();
|
|
|
|
if((tm-last_change) < enc_debounce_ms) return;
|
|
last_change = tm;
|
|
|
|
const bool A = HAL_GPIO_ReadPin(ENCODER_A_GPIO_Port, ENCODER_A_Pin);
|
|
const bool B = HAL_GPIO_ReadPin(ENCODER_B_GPIO_Port, ENCODER_B_Pin);
|
|
|
|
int32_t state = 0;
|
|
if(GPIO_Pin==ENCODER_A_Pin) {
|
|
if(B==0) state--;
|
|
else state++;
|
|
}
|
|
else if(GPIO_Pin==ENCODER_B_Pin) {
|
|
if(A==1) state--;
|
|
else state++;
|
|
}
|
|
|
|
if(state==0) return;
|
|
|
|
if(tm-enc_state_last_change > 50) { // slow down the changes
|
|
|
|
// prevent abrupt direction change
|
|
if(state==state_last) {
|
|
enc_state_last_change = tm;
|
|
user_input_state.encoder += state;
|
|
}
|
|
state_last = state;
|
|
}
|
|
}
|
|
|
|
void ui_init(){
|
|
HAL_GPIO_WritePin(DISP_BLK_GPIO_Port, DISP_BLK_Pin, 1);
|
|
ST7789_Init();
|
|
/*
|
|
HAL_Delay(500);
|
|
|
|
uint16_t back = 0x0000;
|
|
for(int i=0; i<8; i++){
|
|
back += 0x1111;
|
|
ST7789_Fill_Color(back);
|
|
HAL_Delay(10);
|
|
}
|
|
*/
|
|
ST7789_Fill_Color(WHITE);
|
|
//HAL_Delay(300);
|
|
ST7789_DrawImage(0, 0, 280, 240, (uint16_t *)img_splash);
|
|
HAL_Delay(1000);
|
|
|
|
ST7789_Fill_Color(BLACK);
|
|
|
|
// initialize UI controls
|
|
HAL_GPIO_EXTI_Callback(BUTTON_Pin);
|
|
HAL_GPIO_EXTI_Callback(ENCODER_SW_Pin);
|
|
HAL_GPIO_EXTI_Callback(ENCODER_A_Pin);
|
|
HAL_GPIO_EXTI_Callback(ENCODER_B_Pin);
|
|
|
|
}
|
|
|
|
|
|
void format_voltage_string(char *str, int32_t voltage) {
|
|
const int32_t full = voltage/1000;
|
|
const int32_t frac = (voltage-full*1000)/10;
|
|
snprintf(str, 25, "%ld.%02ldV", full, frac);
|
|
}
|
|
|
|
void ui_task(void *argument){
|
|
(void)argument;
|
|
|
|
uint32_t btn_last = 1;
|
|
uint32_t enc_sw_last = 1;
|
|
|
|
ui_function_t ui_func = DAC_SET;
|
|
|
|
bool refresh_display = true;
|
|
|
|
const uint32_t ch[3] = {TIM_CHANNEL_1, TIM_CHANNEL_2, TIM_CHANNEL_3};
|
|
int curr = 0;
|
|
int32_t p = htim4.Init.Period/4;
|
|
for(int i=0; i<3; i++){
|
|
__HAL_TIM_SET_COMPARE(&htim4, ch[i], 0);
|
|
HAL_TIM_PWM_Start(&htim4, ch[i]);
|
|
}
|
|
|
|
uint32_t last_adc_trigger = 0;
|
|
|
|
char volt_in_dc[25] = "xx.xxV";
|
|
char volt_in_usb0[25] = "xx.xxV";
|
|
char volt_in_usb1[25] = "xx.xxV";
|
|
int volt_in_selected = 0;
|
|
|
|
char aux_state_volt[25] = "xx.xxV";
|
|
char aux_state_current[25] = "xxxxmA";
|
|
char aux_meas_volt[25] = "xx.xxV";
|
|
char aux_meas_current[25] = "xxxxmA";
|
|
bool aux_enabled = false;
|
|
|
|
char source_enabled = false;
|
|
char source_state_volt[25] = "xx.xxV";
|
|
char source_state_current_lim[35] = "(xxxx, xxxx) mA";
|
|
char source_meas_volt[25] = "xx.xxV";
|
|
char source_meas_current[25] = "xxxxmA";
|
|
|
|
uint32_t enc_last = user_input_state.encoder;
|
|
// task loop
|
|
while(true) {
|
|
|
|
// LED fading (move to the separate task or function)
|
|
__HAL_TIM_SET_COMPARE(&htim4, ch[curr], p);
|
|
p-=100;
|
|
if(p<=0){
|
|
p = (int32_t)(htim4.Init.Period/4);
|
|
curr++;
|
|
if(curr==3) curr = 0;
|
|
}
|
|
osDelay(10);
|
|
|
|
// update encoder state for display
|
|
const uint32_t enc_sw = user_input_state.enc_sw;
|
|
uint32_t enc = user_input_state.encoder;
|
|
|
|
if (enc!=enc_last) {
|
|
enc_last = enc;
|
|
if (enc<0) {
|
|
enc = 0;
|
|
}
|
|
if (enc>150) {
|
|
enc = 150;
|
|
}
|
|
refresh_display = true;
|
|
}
|
|
|
|
if(HAL_GetTick()-last_adc_trigger > 300){
|
|
last_adc_trigger = HAL_GetTick();
|
|
const int32_t* adc_values = jf_adc_get_values();
|
|
|
|
// format and sort input voltages
|
|
format_voltage_string(volt_in_dc, adc_values[JF_ADC_VSENSE_DC]);
|
|
format_voltage_string(volt_in_usb0, adc_values[JF_ADC_VSENSE_USB0]);
|
|
format_voltage_string(volt_in_usb1, adc_values[JF_ADC_VSENSE_USB1]);
|
|
if (adc_values[JF_ADC_VSENSE_DC]>adc_values[JF_ADC_VSENSE_USB0] && adc_values[JF_ADC_VSENSE_DC]>adc_values[JF_ADC_VSENSE_USB1]) {
|
|
volt_in_selected = 0;
|
|
}
|
|
else {
|
|
if (adc_values[JF_ADC_VSENSE_USB0]>adc_values[JF_ADC_VSENSE_USB1]) {
|
|
volt_in_selected = 1;
|
|
}
|
|
else {
|
|
volt_in_selected = 2;
|
|
}
|
|
}
|
|
|
|
// TODO: add set voltage and current voltage
|
|
format_voltage_string(aux_meas_volt, jf_vaux_measure_voltage());
|
|
snprintf(aux_meas_current, sizeof(aux_meas_current), "%4ldmA", jf_vaux_measure_current());
|
|
format_voltage_string(aux_state_volt, jf_vaux_get_voltage());
|
|
snprintf(aux_state_current, sizeof(aux_state_current), "%4ldmA", jf_vaux_get_current_limit());
|
|
aux_enabled = jf_vaux_is_enabled();
|
|
|
|
source_enabled = jf_routing_output_status();
|
|
const jf_measure_data_t source_data = jf_measure_get_current_values();
|
|
format_voltage_string(source_state_volt, jf_source_get_voltage());
|
|
int32_t source_lim_pos, source_lim_neg;
|
|
jf_source_get_current_limit(&source_lim_pos, &source_lim_neg);
|
|
snprintf(source_state_current_lim, sizeof(source_state_current_lim), "(-%ld, %ld) mA", source_lim_neg, source_lim_pos);
|
|
format_voltage_string(source_meas_volt, (int32_t)(source_data.Vsense*1000));
|
|
snprintf(source_meas_current, sizeof(source_meas_current), "%4ldmA", (int32_t)(source_data.Isense1));
|
|
refresh_display = true;
|
|
}
|
|
|
|
if(enc_sw!=enc_sw_last) {
|
|
enc_sw_last = enc_sw;
|
|
if(!enc_sw) {
|
|
|
|
/*
|
|
if(ui_func==ADC_GET) {
|
|
printf("average frames per request: %ld\r\n", jf_measure_avg_frames_parsed());
|
|
printf("average buffer full: %ld\r\n", jf_measure_avg_buffer_full());
|
|
|
|
}
|
|
else if(ui_func==RANGE) {
|
|
uint8_t range = enc;
|
|
if(range>6) range = 6;
|
|
jf_measure_set_range(range, false);
|
|
printf("send RANGE command: %d\r\n", range);
|
|
}
|
|
else if(ui_func==LED_BLINK) { // FPGA command 0x05
|
|
jf_qspi_add_to_queue(
|
|
JF_CMD_LED_BLINK,
|
|
enc,
|
|
NULL,
|
|
0,
|
|
false
|
|
);
|
|
}
|
|
*/
|
|
if(ui_func==DAC_SET) { // FPGA command 0x06
|
|
jf_source_set_voltage(enc*100, false);
|
|
printf("DAC_SET to %ld mV\r\n", enc*100);
|
|
}
|
|
else if(ui_func==ISET_DAC) {
|
|
const uint16_t val = enc*5;
|
|
jf_source_set_current_limit(val, JF_CURRENT_LIMIT_BOTH, false);
|
|
printf("send ISET_DAC command value %d\r\n", val);
|
|
}
|
|
else if (ui_func==EXTIN) {
|
|
jf_routing_extin_en(enc>0);
|
|
}
|
|
else if (ui_func==VAUX_SET) {
|
|
if (enc<18) {
|
|
jf_vaux_enable(false);
|
|
}
|
|
else {
|
|
jf_vaux_enable(true);
|
|
jf_vaux_set_current_limit(80);
|
|
printf("set voltage to %ld, %d\r\n", enc*100, jf_vaux_set_voltage(enc*100, false));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// switch function
|
|
const uint32_t btn = user_input_state.btn;
|
|
if(btn!=btn_last) {
|
|
btn_last = btn;
|
|
if(!btn) {
|
|
ui_func++;
|
|
if(ui_func==UI_FUNC_COUNT) ui_func = DAC_SET;
|
|
printf("ui_func: %s\r\n", ui_func_labels[ui_func]);
|
|
refresh_display = true;
|
|
}
|
|
}
|
|
|
|
if(refresh_display){
|
|
refresh_display = false;
|
|
char buf[10];
|
|
|
|
ST7789_WriteString(5, 20, "VDC=", Font_7x10, WHITE, BLACK);
|
|
ST7789_WriteString(90, 20, "USB0=", Font_7x10, WHITE, BLACK);
|
|
ST7789_WriteString(180, 20, "USB1=", Font_7x10, WHITE, BLACK);
|
|
|
|
const int vtop_off = 35;
|
|
ST7789_WriteString(5+vtop_off, 20, volt_in_dc, Font_7x10, WHITE, BLACK);
|
|
ST7789_WriteString(90+vtop_off, 20, volt_in_usb0, Font_7x10, WHITE, BLACK);
|
|
ST7789_WriteString(180+vtop_off, 20, volt_in_usb1, Font_7x10, WHITE, BLACK);
|
|
ST7789_DrawRectangle(3, 17, 85, 32, volt_in_selected==0 ? LIGHTGREEN : BLACK);
|
|
ST7789_DrawRectangle(86, 17, 175, 32, volt_in_selected==1 ? LIGHTGREEN : BLACK);
|
|
ST7789_DrawRectangle(176, 17, 270, 32, volt_in_selected==2 ? LIGHTGREEN : BLACK);
|
|
|
|
ST7789_WriteString(5, 60, aux_enabled ? "AUX ON " : "AUX OFF", Font_11x18, aux_enabled ? RED : WHITE, BLACK);
|
|
ST7789_WriteString(100, 60, aux_meas_volt, Font_11x18, WHITE, BLACK);
|
|
ST7789_WriteString(175, 60, aux_meas_current, Font_11x18, WHITE, BLACK);
|
|
ST7789_WriteString(100, 80, aux_state_volt, Font_7x10, WHITE, BLACK);
|
|
ST7789_WriteString(175, 80, aux_state_current, Font_7x10, WHITE, BLACK);
|
|
|
|
ST7789_WriteString(5, 120, source_enabled ? "OUT ON " : "OUT OFF", Font_11x18, source_enabled ? RED : WHITE, BLACK);
|
|
ST7789_WriteString(100, 120, source_meas_volt, Font_11x18, WHITE, BLACK);
|
|
ST7789_WriteString(175, 120, source_meas_current, Font_11x18, WHITE, BLACK);
|
|
ST7789_WriteString(100, 140, source_state_volt, Font_7x10, WHITE, BLACK);
|
|
ST7789_WriteString(155, 140, source_state_current_lim, Font_7x10, WHITE, BLACK);
|
|
|
|
ST7789_WriteString(110, 150, HAL_GPIO_ReadPin(ENABLE_EXT_IN_GPIO_Port, ENABLE_EXT_IN_Pin) ? "EXT IN":" ", Font_16x26, GREEN, BLACK);
|
|
|
|
ST7789_WriteString(5, 175, ui_func_labels[ui_func], Font_16x26, LIGHTBLUE, BLACK);
|
|
ST7789_WriteString(5, 200, "enc:", Font_16x26, WHITE, BLACK);
|
|
|
|
ST7789_WriteString(75, 200, " ", Font_16x26, WHITE, BLACK); // clear
|
|
ST7789_WriteString(75, 200, itoa(enc, buf, 10), Font_16x26, WHITE, BLACK);
|
|
}
|
|
}
|
|
}
|