Files
microchip-application-bmd38…/edc20_cycle_iv_mode.c
T
2024-06-27 21:30:37 +08:00

501 lines
13 KiB
C

#include "edc.h"
#include "elite_board.h"
#include "dac_drv.h"
#include "nrf.h"
#include "nrf_log.h"
#include "FreeRTOS.h"
#include "elite_board.h"
#include "semphr.h"
#include "task.h"
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#if (DEF_ELITE_MODEL == DEF_ELITE_EDC_20)
#define OUT_0 DAC0
#define OUT_1 DAC1
typedef struct __PACKED
{
uint32_t notify_time;
int32_t ch1_data;
int32_t ch2_data;
int32_t ch3_data;
uint16_t cycle;
uint8_t finish_flag;
uint32_t bat_volt;
uint8_t packet_seq;
int32_t ch4_data;
int32_t ch5_data;
int32_t ch6_data;
} payload_t;
typedef struct __PACKED
{
uint8_t mem_board_id;
payload_t payload;
uint8_t : 8;
uint8_t : 8;
uint8_t : 8;
} elite_notify_packet_t;
typedef struct
{
uint32_t id;
uint32_t mS_period;
elite_dac_config_t config;
} iv_cycle_mode_param_t;
const edc20_dac_cal_data_t edc20_dac_cal_data = {
.dac_c = { 2.9701475, 121.9763670 },
.dac_f = {
[0] = { 65.7454092, -290.3872456, -36.65060000 },
[1] = { 27.4300538, -100.6332479, -37.39872222 },
[2] = { 7.61192880, -0.568019000, -40.99282222 } }
};
#define FS_1000mV 1000
#define FS_2800mV 2800
#define FS_8000mV 8000
const float edc20_range_mV[] = {
[0] = FS_1000mV,
[1] = FS_2800mV,
[2] = FS_8000mV,
};
static SemaphoreHandle_t semphr_start = NULL;
static TaskHandle_t task_handle = NULL;
static bool running = false;
extern ret_code_t le_event_notify(uint8_t *p_value, uint16_t len);
static ret_code_t _send_start_packet(elite_notify_packet_t *p_buf, uint32_t loops)
{
memset(&p_buf->payload, 0x00, sizeof(p_buf->payload));
for (uint32_t i = 0; i < loops; i++)
{
ret_code_t ret = le_event_notify((void *)p_buf, sizeof(*p_buf));
if (ret != NRF_SUCCESS)
{
return ret;
}
}
return NRF_SUCCESS;
}
static ret_code_t _send_data_packet(elite_notify_packet_t *p_notify_buf, bool is_last_notify)
{
static int32_t ch1 = 0;
static int32_t ch2 = 0;
static int32_t ch3 = 0;
ch1 += 100;
ch2++;
ch3 = ch2;
p_notify_buf->payload.notify_time = xTaskGetTickCount();
p_notify_buf->payload.ch1_data = ch1;
p_notify_buf->payload.ch2_data = ch2;
p_notify_buf->payload.ch3_data = ch3;
p_notify_buf->payload.bat_volt = 3600;
p_notify_buf->payload.packet_seq++;
p_notify_buf->payload.finish_flag = is_last_notify;
return le_event_notify((void *)p_notify_buf, sizeof(*p_notify_buf));
}
typedef struct
{
float dir;
float mV_output;
float mV_max;
float mV_min;
float mV_start;
float mV_stop;
float step;
uint32_t cycle_cnt;
uint32_t cycle_max;
uint32_t fullscale;
struct
{
float eta_c;
float eta_f;
float Voffset;
float Vc;
float Nc;
float Nc0;
float Nf;
};
} cycle_iv_dac_t;
typedef struct
{
uint32_t period;
} cycle_iv_adc_t;
static uint32_t mV_out_0(cycle_iv_dac_t *p)
{
for (uint32_t i = 0; i < COUNTOF(edc20_range_mV); i++)
{
if ((p->mV_max - p->mV_min) <= edc20_range_mV[i])
{
p->fullscale = edc20_range_mV[i];
p->eta_c = edc20_dac_cal_data.dac_c.coeff;
p->eta_f = edc20_dac_cal_data.dac_f[i].coeff;
p->Voffset = edc20_dac_cal_data.dac_f[i].Voffset;
break;
}
}
p->Vc = (p->mV_max + p->mV_min) / 2;
p->Nc = round((p->Vc - p->Voffset) * p->eta_c) + 32768;
p->Nc0 = round((0 - p->Voffset) * p->eta_c) + 32768;
return p->Nc;
}
static uint32_t mV_out_1(cycle_iv_dac_t *p)
{
p->Nf = round((p->mV_output - p->Vc - p->Voffset - (p->Nc0 - 32768) / p->eta_c) * p->eta_f) + 32768;
return p->Nf;
}
static uint32_t cal_dac_timer_interval(elite_dac_config_t *p_config, cycle_iv_dac_t *p_cycle_iv_dac)
{
uint32_t intvl;
float step_time = p_config->uS_step;
for (intvl = 100; intvl < 1000000; intvl *= 10)
{
p_cycle_iv_dac->step = (p_config->mV_step * intvl) / step_time;
if (p_cycle_iv_dac->step >= 0.001)
{
return intvl;
}
}
return intvl;
}
static void dac_select_circuit(cycle_iv_dac_t *p)
{
float scan_range = p->mV_max - p->mV_min;
if (scan_range <= FS_1000mV)
{
circuit_selection_dac_fine_tune_f0();
}
else if (scan_range <= FS_2800mV)
{
circuit_selection_dac_fine_tune_f1();
}
else if (scan_range <= FS_8000mV)
{
circuit_selection_dac_fine_tune_f2();
}
}
void _callback(void *p_arg)
{
cycle_iv_dac_t *p = p_arg;
if (p->mV_output <= p->mV_min)
{
p->mV_output = p->mV_min;
p->dir = 1;
}
if (p->mV_output >= p->mV_max)
{
p->mV_output = p->mV_max;
p->dir = -1;
}
dac_write_through(OUT_1, mV_out_1(p));
if (p->mV_output == p->mV_start)
{
p->cycle_cnt++;
if (p->cycle_cnt > p->cycle_max)
{
running = false;
}
}
p->mV_output += p->dir * p->step;
}
static void edc20_cycle_iv_mode_task(void *p_arg)
{
elite_notify_packet_t packet_buf;
cycle_iv_dac_t dac_param;
cycle_iv_adc_t adc_param;
iv_cycle_mode_param_t mode_param;
taskENTER_CRITICAL();
/* copy iv cycle parameter */
memcpy(&mode_param, p_arg, sizeof(mode_param));
memset(&packet_buf, 0x00, sizeof(packet_buf));
memset(&dac_param, 0x00, sizeof(dac_param));
memset(&adc_param, 0x00, sizeof(adc_param));
taskEXIT_CRITICAL();
if (1)
{
char info[256];
snprintf(info, 256, "%s() @ %p start", __FUNCTION__, xTaskGetCurrentTaskHandle());
NRF_LOG_INFO("%s", info);
snprintf(info, 256, "%16s:%8ld", "id", mode_param.id);
NRF_LOG_INFO("%s", info);
snprintf(info, 256, "%16s:%7.0fmV", "V_start", mode_param.config.mV_start);
NRF_LOG_INFO("%s", info);
snprintf(info, 256, "%16s:%7.0fmV", "V_stop", mode_param.config.mV_stop);
NRF_LOG_INFO("%s", info);
snprintf(info, 256, "%16s:%7.0fmV", "uV_step", mode_param.config.mV_step);
NRF_LOG_INFO("%s", info);
snprintf(info, 256, "%16s:%8ldus", "uS_step_time", mode_param.config.uS_step);
NRF_LOG_INFO("%s", info);
snprintf(info, 256, "%16s:%8ld", "cycles", mode_param.config.cycles);
NRF_LOG_INFO("%s", info);
snprintf(info, 256, "%16s:%8ldms", "mS_period", mode_param.mS_period);
NRF_LOG_INFO("%s", info);
}
/* set memborad id */
packet_buf.mem_board_id = mode_param.id;
/* send start packet 4 times */
_send_start_packet(&packet_buf, 4);
dac_param.mV_output = mode_param.config.mV_start;
dac_param.mV_max = MAX(mode_param.config.mV_start, mode_param.config.mV_stop);
dac_param.mV_min = MIN(mode_param.config.mV_start, mode_param.config.mV_stop);
dac_param.mV_start = mode_param.config.mV_start;
dac_param.mV_stop = mode_param.config.mV_stop;
dac_param.dir = dac_param.mV_output == dac_param.mV_min ? 1 : -1;
dac_param.cycle_cnt = 0;
dac_param.cycle_max = mode_param.config.cycles;
dac_param.fullscale = 0;
if (1)
{
NRF_LOG_INFO("%s", "");
mV_out_0(&dac_param);
char info[256];
snprintf(info, 256, "%16s:%10.3f", "eta_c", dac_param.eta_c);
NRF_LOG_INFO("%s", info);
snprintf(info, 256, "%16s:%10.3f", "eta_f", dac_param.eta_f);
NRF_LOG_INFO("%s", info);
snprintf(info, 256, "%16s:%10.3f", "Voffset", dac_param.Voffset);
NRF_LOG_INFO("%s", info);
snprintf(info, 256, "%16s:%10.3f", "Vc", dac_param.Vc);
NRF_LOG_INFO("%s", info);
snprintf(info, 256, "%16s:%10.3f", "Nc", dac_param.Nc);
NRF_LOG_INFO("%s", info);
snprintf(info, 256, "%16s:%10.3f", "Nc0", dac_param.Nc0);
NRF_LOG_INFO("%s", info);
dac_param.mV_output = dac_param.mV_start;
mV_out_1(&dac_param);
snprintf(info, 256, "%16s:%10.3f", "V1 Nf", dac_param.Nf);
NRF_LOG_INFO("%s", info);
dac_param.mV_output = dac_param.mV_stop;
mV_out_1(&dac_param);
snprintf(info, 256, "%16s:%10.3f", "V2 Nf", dac_param.Nf);
NRF_LOG_INFO("%s", info);
}
dac_write_through(OUT_0, mV_out_0(&dac_param));
dac_param.mV_output = dac_param.mV_start;
dac_write_through(OUT_1, mV_out_1(&dac_param));
dac_select_circuit(&dac_param);
/* start DAC timer */
edc20_dac_tim_start(cal_dac_timer_interval(&mode_param.config, &dac_param), _callback, &dac_param);
/* start ADC timer */
edc20_adc_tim_start(&mode_param.config);
/* get current tick */
TickType_t tick = xTaskGetTickCount();
uint32_t notify_delay = pdMS_TO_TICKS(mode_param.mS_period);
/* start data update process */
running = true;
while (running)
{
ret_code_t ret = _send_data_packet(&packet_buf, false);
switch (ret)
{
case NRF_SUCCESS:
case NRF_ERROR_RESOURCES:
vTaskDelayUntil(&tick, notify_delay);
break;
default:
running = false;
break;
}
}
edc20_dac_tim_stop();
edc20_adc_tim_stop();
dac_init();
if (1)
{
char info[256];
snprintf(info, 256, "%s() @ %p stop", __FUNCTION__, xTaskGetCurrentTaskHandle());
NRF_LOG_INFO("%s", info);
}
vTaskDelete(NULL);
}
void edc20_cycle_iv_mode_init(void)
{
}
#define VDIRECTION(v1, v2) ((v1 > v2) ? 0 : 1)
// Step time macro
#define STEPTIME_HALF_SEC 5000
#define STEPTIME_ONE_SEC 10000
#define STEPTIME_TWO_SEC 20000
static uint32_t step2VsetRate(uint32_t step)
{
/*step = 100 mv, index = 0, n = 2
10 mv, index = 1, n = 10
1 mv, index = 2, n = 100
0.1 mv, index = 3, n = 1000
0.01mv, index = 4, n = 10000 */
if (step >= 10000)
{
return 0;
}
else if (step >= 1000)
{
return 1;
}
else if (step >= 100)
{
return 2;
}
else if (step >= 10)
{
return 3;
}
else if (step >= 1)
{
return 4;
}
else
{
return 5;
}
}
static uint32_t get_step_time(uint8_t StepTime)
{
switch (StepTime)
{
case 0: { // 0.5 sec
return STEPTIME_HALF_SEC;
}
case 1: { // 1 sec
return STEPTIME_ONE_SEC;
}
case 2: { // 2 sec
return STEPTIME_TWO_SEC;
}
default: { // 1 sec
return STEPTIME_ONE_SEC;
}
}
}
#define STEP_TO_VSETRATE(step) step2VsetRate(step)
const uint32_t VsetRateTable[5] = { 2, 10, 100, 1000, 10000 };
static uint32_t convt_uS_step(uint32_t idx)
{
switch (idx)
{
case 0: { // 0.5 sec
return 500000;
}
case 1: { // 1 sec
return 1000000;
}
case 2: { // 2 sec
return 2000000;
}
default: { // 1 sec
return 1000000;
}
}
}
void edc20_cycle_iv_mode_start(uint8_t *ins, uint16_t size)
{
/*
instru.eliteFxn = CURVE_IV_CY;
instru.Ve1 = ((uint16_t)(ins[3]) << 8) | (uint16_t)(ins[4]);
instru.Ve2 = ((uint16_t)(ins[5]) << 8) | (uint16_t)(ins[6]);
instru.Vinit = (int32_t)instru.Ve1;
instru.Vmax = (int32_t)VMAX(instru.Ve1,instru.Ve2);
instru.Vmin = (int32_t)VMIN(instru.Ve1,instru.Ve2);
instru.directionInit = VDIRECTION(instru.Ve1,instru.Ve2);
instru.steptime = get_step_time(ins[9]); //5000;10000;20000;
instru.step = ((uint32_t)(ins[7]) << 8) | (uint32_t)(ins[8]);//1~1000 = 0.1mv ~ 100mv
instru.step = instru.step * 100000 / instru.steptime;
STEP_TO_VSETRATE(instru.step);
instru.VsetRate = VsetRateTable[instru.VsetRateIndex];//N
instru.cycleNumber = ((uint16_t)(ins[10]) << 8) | (uint16_t)(ins[11]);
instru.hign_z_en = ins[13] & 0x0F;
instru.notifyRate = ((uint32_t)ins[14] << 8) | (uint32_t)ins[15];
instru.notifyRate = 10000 / instru.notifyRate * 10;
*/
struct __PACKED
{
uint8_t id : 4;
uint8_t : 4;
uint8_t : 8;
uint8_t : 8;
uint16_t volt_start; // unit: 100uV, -5V = 0, 0V = 25000, 5V = 50000
uint16_t volt_stop; // unit: 100uV, -5V = 0, 0V = 25000, 5V = 50000
uint16_t step; // unit: 100uV
uint8_t step_time; // enum: 0 = 5000us, 1 = 10000us, 2 = 20000us
uint16_t cycles; // 0 ~ 500000
uint8_t : 8;
uint8_t hi_z_en; // lower nibble
uint16_t sample_rate; // unit: 0.1Hz
} *p = (void *)ins;
iv_cycle_mode_param_t mode_param = {
.id = p->id,
.mS_period = 1000 * 10 / __REVSH(p->sample_rate),
.config.mV_start = ((__REVSH(p->volt_start) & 0xFFFF) / 10 - 2500) * 2,
.config.mV_stop = ((__REVSH(p->volt_stop) & 0xFFFF) / 10 - 2500) * 2,
.config.mV_step = (uint32_t)__REVSH(p->step) / 10,
.config.uS_step = convt_uS_step(p->step_time),
.config.cycles = (__REVSH(p->cycles) & 0xFFFF)
};
xTaskCreate(edc20_cycle_iv_mode_task, "iv_mode", 2048, (void *)&mode_param, 3, &task_handle);
portYIELD();
}
#endif /* ! DEF_ELITE_MODEL */