501 lines
13 KiB
C
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 */
|