This commit is contained in:
Ta-Shun Su
2019-05-23 18:52:30 +08:00
parent ba2fb3eb1e
commit df182c9ab7
4 changed files with 323 additions and 322 deletions
@@ -24,7 +24,7 @@ TODO
==== product information ====
===========================*/
#define DEVICE_NAME "NeuliveSTI-M0.1"
#define DEVICE_NAME "NeuliveSTI"
#define MAJOR_PRODUCT_NUMBER 1
#define MINOR_PRODUCT_NUMBER 2
#define MAJOR_VERSION_NUMBER 1
@@ -46,6 +46,9 @@ TODO
#define RIS_LOCAL 0x40
#define RIS_CHANNEL 0x80
// ask sti remain times
#define DEBUG_INS_TIMES 0x10
// ask device sleeping
#define DEBUG_INS_SLEEP 0x50
#define STI_WAVEFORM_POS 0x00
@@ -59,13 +62,37 @@ TODO
==== include ====
================*/
#define HEADSTAGE_PIN_USE_CC26XX
#include "headstage_debug.h"
#include "headstage_power.h"
#include "headstage_pin.h"
#include "sti/headstage_adc.h"
#include "sti/headstage_gptimer.h"
#include "sti/headstage_pwm.h"
static uint32_t cpu_frequency;
#ifdef headstage_gptimer_set_frequency
#undef headstage_gptimer_set_frequency
#define headstage_gptimer_set_frequency(gptimer_handle, frequency) \
do { \
uint32_t _frequency = (uint32_t)(frequency); \
GPTimerCC26XX_Value _load = cpu_frequency / _frequency - 1; \
_load = (_load < 0xFFFF) ? _load : ((0xFA0000 | (_load / 250)) - 1); \
GPTimerCC26XX_setLoadValue(gptimer_handle, _load); \
} while (0)
#endif
#ifdef headstage_gptimer_set_timeout
#undef headstage_gptimer_set_timeout
#define headstage_gptimer_set_timeout(gptimer_handle, timeout_us) \
do { \
GPTimerCC26XX_Value _load = (timeout_us)*cpu_frequency / 1000000 - 1; \
_load = (_load < 0xFFFF) ? _load : ((0xFA0000 | (_load / 250)) - 1); \
GPTimerCC26XX_setLoadValue(gptimer_handle, _load); \
} while (0)
#endif
/*=================================
==== constant parameter table ====
================================*/
@@ -75,44 +102,72 @@ TODO
========================*/
typedef struct {
uint8_t enable;
uint8_t mode;
uint8_t precision;
uint16_t frequency;
uint16_t pulse_width;
uint16_t pw_ipi;
uint16_t times;
/**
* enable channel
*/
uint8_t enable;
/**
* low frequency counter.
* waveform
*/
int low_freq_counter;
uint8_t mode;
/**
* frequency factor
*/
uint8_t precision;
/**
* pulse frequency
*/
uint16_t frequency;
/**
* pulse width
*/
uint16_t pulse_width;
/**
* pulse internal pulse interval
*/
uint16_t pw_ipi;
/**
* stimulation times
*/
uint8_t times;
} NeuLiveStiChanelParameter;
typedef struct {
uint8_t pon;
uint8_t pol;
uint8_t stage;
} NeuLiveStiChanelState;
struct HEADSTAGE_PARAMETER_TABLE {
uint32_t duty_cycle;
NeuLiveStiChanelParameter channel[TOTAL_CHANNEL_NUMBER];
NeuLiveStiChanelState state[TOTAL_CHANNEL_NUMBER];
} INSTRUCTION = {0};
#define reset_parameter_table() memset(&INSTRUCTION, 0, sizeof(struct HEADSTAGE_PARAMETER_TABLE));
#define reset_parameter_table() \
do { \
memset(&INSTRUCTION, 0, sizeof(struct HEADSTAGE_PARAMETER_TABLE)); \
INSTRUCTION.state[CHANNEL_STI_0].pon = PIN_PON0; \
INSTRUCTION.state[CHANNEL_STI_0].pol = PIN_POL0; \
INSTRUCTION.state[CHANNEL_STI_1].pon = PIN_PON1; \
INSTRUCTION.state[CHANNEL_STI_1].pol = PIN_POL1; \
} while (0)
#define actual_channel_frequency(p) (p->frequency / (p->precision ? 10 : 1))
#define is_low_frequency(p) ((p->frequency < 4 && p->precision == 0) || (p->frequency < 2000 && p->precision == 1))
#define infinite_times(p) (p->times >= 1000)
static GPTimerCC26XX_Handle headstage_gptimer_handle[] = {
//
gptimer_handle_2,
gptimer_handle_0,
gptimer_handle_1,
//
};
static ADC_Handle headstage_adc_handle[] = {
//
headstage_adc_handle_2,
headstage_adc_handle_0,
headstage_adc_handle_1,
gptimer_handle_2,
//
};
@@ -129,25 +184,6 @@ static void headstage_sti_collect_stimulation_information();
=======================*/
static void headstage_sti_event() {
if (flag_mask(EVT_PERIODIC_GPTIMER_0)) {
flag_disable(EVT_PERIODIC_GPTIMER_0);
headstage_sti_pulse_event(CHANNEL_STI_0);
}
if (flag_mask(EVT_PERIODIC_GPTIMER_1)) {
flag_disable(EVT_PERIODIC_GPTIMER_1);
headstage_sti_pulse_event(CHANNEL_STI_1);
}
if (flag_mask(EVT_PERIODIC_GPTIMER_2)) {
flag_disable(EVT_PERIODIC_GPTIMER_2);
headstage_sti_collect_recording_data(CHANNEL_BATTERY);
headstage_sti_collect_stimulation_information();
}
if (EVENT_MASK == 0) {
// fast return
return;
@@ -164,158 +200,132 @@ static void headstage_sti_event() {
static void headstage_init() {
headstage_pin_open();
Types_FreqHz cpu_freq;
BIOS_getCpuFreq(&cpu_freq);
cpu_frequency = cpu_freq.lo;
headstage_gptimer_open();
headstage_pwm_open();
headstage_adc_open();
headstage_gptimer_set_frequency(headstage_gptimer[CHANNEL_BATTERY], 200);
headstage_pwm_start();
headstage_pin_output(PIN_STI_0, 0);
headstage_pin_output(PIN_SET_1, 0);
headstage_pin_output(PIN_SET_3, 1);
headstage_pin_output(PIN_SET_5, 0);
headstage_pin_output(PIN_SET_6, 0);
headstage_pin_output(PIN_SET_10, 0);
headstage_pin_output(PIN_SET_11, 0);
headstage_pin_output(PIN_POL0, 0);
headstage_pin_output(PIN_POL1, 0);
headstage_pin_output(PIN_PON0, 0);
headstage_pin_output(PIN_PON1, 0);
headstage_pin_output(PIN_TPS, 1);
}
static void headstage_update_ris_instruction(uint8_t ins_len, uint8_t *instruction) {
uint8_t ins_oper = instruction[0] & 0xE0;
switch (ins_oper) {
case RIS_GLOBAL: {
// 5b11111#header;2b0#GV;12bCURRENT
// --------------------
// 3b001#header#;1bx;12bCURRENT
case RIS_GLOBAL: {
// 3b001#header#;1bx;12bCURRENT
uint16_t a = (uint16_t)(instruction[0]) && 0x0F;
uint16_t b = (uint16_t)(instruction[1]) && 0xFF;
uint16_t current = (a << 8) | b; // actual current output(mA) in 1mA mode (2019/03)
uint16_t a = (uint16_t)(instruction[0]) && 0x0F;
uint16_t b = (uint16_t)(instruction[1]) && 0xFF;
uint16_t current = (a << 8) | b; // actual current output(mA) in 1mA mode (2019/03)
INSTRUCTION.duty_cycle = current;
headstage_pwm_set(MAX_DUTY, current);
break;
}
case RIS_LOCAL: {
// 5b11111#header;2b01#LV
// 3b>channel
// 1b>PRECISION[channel]
// 3b>STI_MODE[channel]
// 12b>STI_FREQ[channel]
// 10b>STI_PW[channel]
// 10b>STI_PW_IPI[channel]
// 10b>STI_NUM[channel]
// --------------------
// 3b010#header;1bx
// 4b>channel
// 3b>STI_MODE[channel]
// 1b>PRECISION[channel]
// 12b>STI_FREQ[channel]
// 10b>STI_PW[channel]
// 10b>STI_PW_IPI[channel]
// 10b>STI_NUM[channel]
uint8_t channel = (instruction[0] & 0x0F);
uint8_t mode = (instruction[1] & 0xE0) >> 5;
uint8_t prec = (instruction[1] & 0x10) >> 4;
uint16_t freq_a = (uint16_t)(instruction[1]) & 0x0F;
uint16_t freq_b = (uint16_t)(instruction[2]) & 0xFF;
uint16_t freq = (freq_a << 8) | freq_b;
uint16_t width_a = (uint16_t)(instruction[3]) & 0xFF;
uint16_t width_b = (uint16_t)(instruction[4]) & 0xC0;
uint16_t width = (width_a << 2) | (width_b >> 6);
uint16_t ipi_a = (uint16_t)(instruction[4]) & 0x3F;
uint16_t ipi_b = (uint16_t)(instruction[5]) & 0xF0;
uint16_t ipi = (ipi_a << 4) | (ipi_b >> 4);
uint16_t times_a = (uint16_t)(instruction[5]) & 0x0F;
uint16_t times_b = (uint16_t)(instruction[6]) & 0xFC;
uint16_t times = (times_a << 6) | (times_b >> 2);
if (channel < TOTAL_CHANNEL_NUMBER - 1) {
NeuLiveStiChanelParameter *p = &INSTRUCTION.channel + 1 + channel;
uint16_t adjust_value = (channel == 0) ? 3 : 5;
if (width > 0) {
// error when output 100us
width += (width * adjust_value / 100) - 1;
}
if (ipi > 0) {
// error when output 100us
ipi += (ipi * adjust_value / 100) - 1;
}
p->mode = mode;
p->precision = prec;
p->frequency = freq;
p->pulse_width = width;
p->pulse_width = width;
p->pw_ipi = ipi;
p->times = times;
}
break;
}
case RIS_CHANNEL: {
// 5b11111#header;2b10#CE
// a0;a1;a2;a3;a4;a5;a6;a7;a8;a9;aa;ab;ac;ad;ae;af
// --------------------
// 3b100#header;5bx;
// a0;a1;a2;a3;a4;a5;a6;a7;a8;a9;aa;ab;ac;ad;ae;af
if (INSTRUCTION.duty_cycle == 0) {
INSTRUCTION.duty_cycle = current;
headstage_pwm_set(MAX_DUTY, current);
break;
}
for (uint8_t channel = 1; channel < TOTAL_CHANNEL_NUMBER; i++) {
NeuLiveStiChanelParameter *p = &INSTRUCTION.channel + channel;
case RIS_LOCAL: {
// 3b010#header;1bx
// 4b>channel
// 3b>STI_MODE[channel]
// 1b>PRECISION[channel]
// 12b>STI_FREQ[channel]
// 10b>STI_PW[channel]
// 10b>STI_PW_IPI[channel]
// 10b>STI_NUM[channel]
uint8_t channel = (instruction[0] & 0x0F);
uint8_t mode = (instruction[1] & 0xE0) >> 5;
uint8_t prec = (instruction[1] & 0x10) >> 4;
uint16_t freq_a = (uint16_t)(instruction[1]) & 0x0F;
uint16_t freq_b = (uint16_t)(instruction[2]) & 0xFF;
uint16_t freq = (freq_a << 8) | freq_b;
uint16_t width_a = (uint16_t)(instruction[3]) & 0xFF;
uint16_t width_b = (uint16_t)(instruction[4]) & 0xC0;
uint16_t width = (width_a << 2) | (width_b >> 6);
uint16_t ipi_a = (uint16_t)(instruction[4]) & 0x3F;
uint16_t ipi_b = (uint16_t)(instruction[5]) & 0xF0;
uint16_t ipi = (ipi_a << 4) | (ipi_b >> 4);
uint16_t times_a = (uint16_t)(instruction[5]) & 0x0F;
uint16_t times_b = (uint16_t)(instruction[6]) & 0xFC;
uint16_t times = (times_a << 6) | (times_b >> 2);
uint8_t index = 1 + (channel - 1) % 8;
uint8_t mask = 1 << (7 - (channel - 1) / 8);
if (channel < TOTAL_CHANNEL_NUMBER - 1) {
NeuLiveStiChanelParameter *p = &INSTRUCTION.channel + 1 + channel;
p->enable = 0;
if ((instruction[index] & mask) != 0) {
uint16_t frequency = actual_channel_frequency(p);
if (is_low_frequency(p)) {
frequency *= 100;
}
if (frequency != 0 && p->pulse_width != 0) {
p->enable = 1;
headstage_gptimer_set_frequency(headstage_gptimer_handle[channel], frequency);
}
p->mode = mode;
p->precision = prec;
p->frequency = freq;
p->pulse_width = width;
p->pulse_width = width;
p->pw_ipi = ipi;
p->times = times;
}
break;
}
break;
}
case RIS_CHANNEL: {
// 3b100#header;5bx;
// a0;a1;a2;a3;a4;a5;a6;a7;a8;a9;aa;ab;ac;ad;ae;af
if (INSTRUCTION.duty_cycle == 0) {
break;
}
for (uint8_t channel = 1; channel < TOTAL_CHANNEL_NUMBER; i++) {
NeuLiveStiChanelParameter *p = &INSTRUCTION.channel + channel;
uint8_t index = 1 + (channel - 1) % 8;
uint8_t mask = 1 << (7 - (channel - 1) / 8);
p->enable = 0;
if ((instruction[index] & mask) != 0) {
if (p->frequency != 0 && p->pulse_width != 0) {
p->enable = 1;
headstage_gptimer_set_frequency(headstage_gptimer_handle[channel], frequency);
}
}
}
break;
}
}
}
static void headstage_update_vis_instruction(uint8_t vis_oper) {
switch (vis_oper) {
case VIS_STI:
headstage_gptimer_start(gptimer_handle_0);
headstage_gptimer_start(gptimer_handle_1);
headstage_gptimer_start(gptimer_handle_2);
break;
case VIS_RST:
headstage_gptimer_stop(gptimer_handle_0);
headstage_gptimer_stop(gptimer_handle_1);
headstage_gptimer_stop(gptimer_handle_2);
reset_parameter_table();
break;
case VIS_INT:
headstage_gptimer_stop(gptimer_handle_0);
headstage_gptimer_stop(gptimer_handle_1);
headstage_gptimer_stop(gptimer_handle_2);
break;
case VIS_STI: {
for (uint8_t channel = 1; channel < TOTAL_CHANNEL_NUMBER; i++) {
NeuLiveStiChanelParameter *p = &INSTRUCTION.channel + channel;
if (p->enable) {
headstage_gptimer_start(headstage_gptimer_handle[channel]);
}
}
break;
}
case VIS_RST: {
for (uint8_t channel = 0; channel < TOTAL_CHANNEL_NUMBER; i++) {
headstage_gptimer_stop(headstage_gptimer_handle[channel]);
}
reset_parameter_table();
break;
}
case VIS_INT: {
for (uint8_t channel = 0; channel < TOTAL_CHANNEL_NUMBER; i++) {
headstage_gptimer_stop(headstage_gptimer_handle[channel]);
}
break;
}
}
}
@@ -323,11 +333,20 @@ static uint8_t headstage_debug_instruction(uint8_t ins_buf) {
uint8_t ins_oper = ins_buf[0] & 0xF0;
switch (ins_oper) {
case DEBUG_INS_SLEEP:
headstage_pin_output(IOID_3, 0);
headstage_power_shutdown();
break;
case DEBUG_INS_TIMES:
for (uint8_t channel = 1; channel < TOTAL_CHANNEL_NUMBER; i++) {
ins_buf[channel] = INSTRUCTION.channel[channel].times;
}
return TOTAL_CHANNEL_NUMBER;
case DEBUG_INS_SLEEP:
headstage_update_vis_instruction(VIS_INT);
headstage_pin_output(PIN_TPS, 0);
headstage_power_shutdown();
break;
}
return 0;
}
/*========================
@@ -336,95 +355,82 @@ static uint8_t headstage_debug_instruction(uint8_t ins_buf) {
static void headstage_sti_pulse_event(uint8_t channel) {
NeuLiveStiChanelParameter *p;
NeuLiveStiChanelState * s;
switch (channel) {
case CHANNEL_STI_0:
case CHANNEL_STI_1:
p = &INSTRUCTION.channel + channel;
break;
case CHANNEL_BATTERY:
default:
return;
case CHANNEL_STI_0:
case CHANNEL_STI_1:
p = &INSTRUCTION.channel + channel;
s = &INSTRUCTION.state + channel;
break;
case CHANNEL_BATTERY:
default:
return;
}
if (!(p->enable && p->times > 0)) {
return;
}
uint8_t p0, p1, p2;
switch (channel) {
case CHANNEL_STI_0:
p0 = PIN_STI_0;
p1 = PIN_SET_10;
p2 = PIN_SET_11;
break;
case CHANNEL_STI_1:
p0 = PIN_STI_1;
p1 = PIN_SET_6;
p2 = PIN_SET_5;
break;
}
switch (p->mode) {
case STI_WAVEFORM_POS:
headstage_pin_output(p1, 0);
headstage_pin_output(p2, 1);
headstage_pin_output(p0, 1);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p2, 0);
break;
case STI_WAVEFORM_NEG:
headstage_pin_output(p1, 1);
headstage_pin_output(p2, 1);
headstage_pin_output(p0, 1);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p2, 0);
break;
case STI_WAVEFORM_P2N:
if (p->pw_ipi == 0) {
headstage_pin_output(p1, 0);
headstage_pin_output(p2, 1);
headstage_pin_output(p0, 1);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p1, 1);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p2, 0);
} else {
case STI_WAVEFORM_POS:
headstage_pin_output(p1, 0);
headstage_pin_output(p2, 1);
headstage_pin_output(p0, 1);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p2, 0);
headstage_cpu_delay_us(p->pw_ipi);
headstage_pin_output(p2, 1);
headstage_pin_output(p1, 1);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p2, 0);
}
break;
case STI_WAVEFORM_N2P:
if (p->pw_ipi == 0) {
headstage_pin_output(p1, 1);
headstage_pin_output(p2, 1);
headstage_pin_output(p0, 1);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p1, 0);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p2, 0);
} else {
break;
case STI_WAVEFORM_NEG:
headstage_pin_output(p1, 1);
headstage_pin_output(p2, 1);
headstage_pin_output(p0, 1);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p2, 0);
headstage_cpu_delay_us(p->pw_ipi);
headstage_pin_output(p2, 1);
headstage_pin_output(p1, 0);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p2, 0);
}
break;
break;
case STI_WAVEFORM_P2N:
if (p->pw_ipi == 0) {
headstage_pin_output(p1, 0);
headstage_pin_output(p2, 1);
headstage_pin_output(p0, 1);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p1, 1);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p2, 0);
} else {
headstage_pin_output(p1, 0);
headstage_pin_output(p2, 1);
headstage_pin_output(p0, 1);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p2, 0);
headstage_cpu_delay_us(p->pw_ipi);
headstage_pin_output(p2, 1);
headstage_pin_output(p1, 1);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p2, 0);
}
break;
case STI_WAVEFORM_N2P:
if (p->pw_ipi == 0) {
headstage_pin_output(p1, 1);
headstage_pin_output(p2, 1);
headstage_pin_output(p0, 1);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p1, 0);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p2, 0);
} else {
headstage_pin_output(p1, 1);
headstage_pin_output(p2, 1);
headstage_pin_output(p0, 1);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p2, 0);
headstage_cpu_delay_us(p->pw_ipi);
headstage_pin_output(p2, 1);
headstage_pin_output(p1, 0);
headstage_cpu_delay_us(p->pulse_width);
headstage_pin_output(p2, 0);
}
break;
}
headstage_sti_collect_recording_data(channel);
@@ -6,6 +6,8 @@
#include <Board.h>
#include <ti/drivers/timer/GPTimerCC26XX.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/family/arm/cc26xx/Power.h>
#include <ti/sysbios/family/arm/cc26xx/PowerCC2650.h>
#include <xdc/runtime/Types.h>
#define EVT_PERIODIC_GPTIMER_0 EVT_PERIODIC_0
@@ -22,23 +24,29 @@ static void headstage_gptimer_callback(GPTimerCC26XX_Handle handle, GPTimerCC26X
#define headstage_gptimer_stop(gptimer_handle) GPTimerCC26XX_stop(gptimer_handle)
#define headstage_gptimer_close(gptimer_handle) GPTimerCC26XX_close(gptimer_handle)
#define headstage_gptimer_open() \
do { \
GPTimerCC26XX_Params params; \
GPTimerCC26XX_Params_init(&params); \
params.width = GPT_CONFIG_16BIT; \
params.mode = GPT_MODE_PERIODIC_DOWN; \
params.debugStallMode = GPTimerCC26XX_DEBUG_STALL_OFF; \
gptimer_handle_0 = GPTimerCC26XX_open(Board_GPTIMER0A, &params); \
gptimer_handle_1 = GPTimerCC26XX_open(Board_GPTIMER1A, &params); \
gptimer_handle_2 = GPTimerCC26XX_open(Board_GPTIMER2A, &params); \
GPTimerCC26XX_setLoadValue(gptimer_handle_0, 0xFFFFFF); \
GPTimerCC26XX_setLoadValue(gptimer_handle_1, 0xFFFFFF); \
GPTimerCC26XX_setLoadValue(gptimer_handle_2, 0xFFFFFF); \
GPTimerCC26XX_registerInterrupt(gptimer_handle_0, headstage_gptimer_callback, GPT_INT_TIMEOUT); \
GPTimerCC26XX_registerInterrupt(gptimer_handle_1, headstage_gptimer_callback, GPT_INT_TIMEOUT); \
GPTimerCC26XX_registerInterrupt(gptimer_handle_2, headstage_gptimer_callback, GPT_INT_TIMEOUT); \
} while (0)
static void headstage_gptimer_open() {
// improve timer accuracy
// Power_setDependency(XOSC_HF);
GPTimerCC26XX_Params params;
GPTimerCC26XX_Params_init(&params);
params.width = GPT_CONFIG_16BIT;
params.mode = GPT_MODE_PERIODIC_DOWN;
params.debugStallMode = GPTimerCC26XX_DEBUG_STALL_OFF;
gptimer_handle_0 = GPTimerCC26XX_open(Board_GPTIMER0A, &params);
gptimer_handle_1 = GPTimerCC26XX_open(Board_GPTIMER1A, &params);
gptimer_handle_2 = GPTimerCC26XX_open(Board_GPTIMER2A, &params);
GPTimerCC26XX_setLoadValue(gptimer_handle_0, 0xFFFFFF);
GPTimerCC26XX_setLoadValue(gptimer_handle_1, 0xFFFFFF);
GPTimerCC26XX_setLoadValue(gptimer_handle_2, 0xFFFFFF);
GPTimerCC26XX_registerInterrupt(gptimer_handle_0, headstage_gptimer_callback, GPT_INT_TIMEOUT);
GPTimerCC26XX_registerInterrupt(gptimer_handle_1, headstage_gptimer_callback, GPT_INT_TIMEOUT);
GPTimerCC26XX_registerInterrupt(gptimer_handle_2, headstage_gptimer_callback, GPT_INT_TIMEOUT);
}
#define headstage_gptimer_set_frequency(gptimer_handle, frequency) \
do { \
@@ -50,4 +58,13 @@ static void headstage_gptimer_callback(GPTimerCC26XX_Handle handle, GPTimerCC26X
GPTimerCC26XX_setLoadValue(gptimer_handle, _load); \
} while (0)
#define headstage_gptimer_set_timeout(gptimer_handle, timeout_us) \
do { \
Types_FreqHz _cpu_freq; \
BIOS_getCpuFreq(&_cpu_freq); \
GPTimerCC26XX_Value _load = (timeout_us)*_cpu_freq.lo / 1000000 - 1; \
_load = (_load < 0xFFFF) ? _load : ((0xFA0000 | (_load / 250)) - 1); \
GPTimerCC26XX_setLoadValue(gptimer_handle, _load); \
} while (0)
#endif // HEADSTAGE_GPTIMER_H
@@ -22,6 +22,7 @@ static PIN_Config headstage_pin_configuration[] = { //
PIN_POL1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL,
PIN_POL0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL,
PIN_PON0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL,
PIN_TPS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL,
//
PIN_TERMINATE};
@@ -146,6 +146,7 @@
extern "C" {
#endif
// clang-format off
#include <xdc/std.h>
#include <stdint.h>
#include <stdbool.h>
@@ -158,14 +159,13 @@ extern "C" {
#include <driverlib/ioc.h>
#include <driverlib/timer.h>
#include <inc/hw_gpt.h>
// clang-format on
/*!
* @brief
* Definitions for specifying the GPTimer configuration (width)
*/
typedef enum GPTimerCC26XX_Width
{
typedef enum GPTimerCC26XX_Width {
GPT_CONFIG_32BIT = GPT_CFG_CFG_32BIT_TIMER,
GPT_CONFIG_16BIT = GPT_CFG_CFG_16BIT_TIMER,
} GPTimerCC26XX_Width;
@@ -178,29 +178,22 @@ typedef enum GPTimerCC26XX_Width
* also updating driver.
*
*/
typedef enum GPTimerCC26XX_Mode
{
typedef enum GPTimerCC26XX_Mode {
/* One shot mode counting upwards */
GPT_MODE_ONESHOT_UP = GPT_TAMR_TAMR_ONE_SHOT | GPT_TAMR_TACDIR_UP | \
GPT_TAMR_TAMIE,
/* Periodic mode counting downwards */
GPT_MODE_PERIODIC_DOWN = GPT_TAMR_TAMR_PERIODIC | GPT_TAMR_TACDIR_DOWN | \
GPT_TAMR_TAMIE,
GPT_MODE_ONESHOT_UP = GPT_TAMR_TAMR_ONE_SHOT | GPT_TAMR_TACDIR_UP | GPT_TAMR_TAMIE,
/* One shot mode counting downwards */
GPT_MODE_ONESHOT_DOWN = GPT_TAMR_TAMR_ONE_SHOT | GPT_TAMR_TACDIR_DOWN | GPT_TAMR_TAMIE,
/* Periodic mode counting upwards */
GPT_MODE_PERIODIC_UP = GPT_TAMR_TAMR_PERIODIC | GPT_TAMR_TACDIR_UP | \
GPT_TAMR_TAMIE,
GPT_MODE_PERIODIC_UP = GPT_TAMR_TAMR_PERIODIC | GPT_TAMR_TACDIR_UP | GPT_TAMR_TAMIE,
/* Periodic mode counting downwards */
GPT_MODE_PERIODIC_DOWN = GPT_TAMR_TAMR_PERIODIC | GPT_TAMR_TACDIR_DOWN | GPT_TAMR_TAMIE,
/* Edge count mode counting upwards */
GPT_MODE_EDGE_COUNT_UP = GPT_TAMR_TAMR_CAPTURE | GPT_TAMR_TACDIR_UP | \
GPT_TAMR_TACM_EDGCNT,
GPT_MODE_EDGE_COUNT_UP = GPT_TAMR_TAMR_CAPTURE | GPT_TAMR_TACDIR_UP | GPT_TAMR_TACM_EDGCNT,
/* Edge count mode counting upwards */
GPT_MODE_EDGE_TIME_UP = GPT_TAMR_TAMR_CAPTURE | GPT_TAMR_TACDIR_UP | \
GPT_TAMR_TACM_EDGTIME,
GPT_MODE_EDGE_TIME_UP = GPT_TAMR_TAMR_CAPTURE | GPT_TAMR_TACDIR_UP | GPT_TAMR_TACM_EDGTIME,
/* PWM mode counting downwards. This specific configuration is used by the
PWM2TimerCC26XX driver */
GPT_MODE_PWM = GPT_TAMR_TAMR_PERIODIC | GPT_TAMR_TACDIR_UP | \
GPT_TAMR_TAAMS_PWM | GPT_TAMR_TACM_EDGCNT | \
GPT_TAMR_TAPLO_CCP_ON_TO | GPT_TAMR_TAPWMIE_EN | \
GPT_TAMR_TAMRSU_CYCLEUPDATE,
GPT_MODE_PWM = GPT_TAMR_TAMR_PERIODIC | GPT_TAMR_TACDIR_UP | GPT_TAMR_TAAMS_PWM | GPT_TAMR_TACM_EDGCNT | GPT_TAMR_TAPLO_CCP_ON_TO | GPT_TAMR_TAPWMIE_EN | GPT_TAMR_TAMRSU_CYCLEUPDATE,
} GPTimerCC26XX_Mode;
/*!
@@ -209,16 +202,15 @@ typedef enum GPTimerCC26XX_Mode
* arguments should be a bit vector containing these definitions.
* See description in Technical Reference
*/
typedef enum GPTimerCC26XX_Interrupt
{
GPT_INT_TIMEOUT = 1 << 0,
GPT_INT_CAPTURE_MATCH = 1 << 1,
GPT_INT_CAPTURE = 1 << 2,
GPT_INT_MATCH = 1 << 3,
typedef enum GPTimerCC26XX_Interrupt {
GPT_INT_TIMEOUT = 1 << 0,
GPT_INT_CAPTURE_MATCH = 1 << 1,
GPT_INT_CAPTURE = 1 << 2,
GPT_INT_MATCH = 1 << 3,
} GPTimerCC26XX_Interrupt;
/* Number of entries in GPTimerCC26XX_Interrupt */
#define GPT_NUM_INTS 4
#define GPT_NUM_INTS 4
/*!
* @brief
@@ -226,8 +218,7 @@ typedef enum GPTimerCC26XX_Interrupt
* Used in GPTimer configuration structure GPTimerCC26XX_config to
* configure the corresponding timer unit.
*/
typedef enum GPTimerCC26XX_Part
{
typedef enum GPTimerCC26XX_Part {
GPT_A = 0,
GPT_B,
GPT_PARTS_COUNT,
@@ -241,8 +232,7 @@ typedef enum GPTimerCC26XX_Part
* @sa PINCC26XX_setMux
* @sa GPTimerCC26XX_getPinMux
*/
typedef enum GPTimerCC26XX_PinMux
{
typedef enum GPTimerCC26XX_PinMux {
GPT_PIN_0A = IOC_PORT_MCU_PORT_EVENT0,
GPT_PIN_0B = IOC_PORT_MCU_PORT_EVENT1,
GPT_PIN_1A = IOC_PORT_MCU_PORT_EVENT2,
@@ -257,8 +247,7 @@ typedef enum GPTimerCC26XX_PinMux
* @brief
* Definitions for controlling timer debug stall mode
*/
typedef enum GPTimerCC26XX_DebugMode
{
typedef enum GPTimerCC26XX_DebugMode {
GPTimerCC26XX_DEBUG_STALL_OFF = 0,
GPTimerCC26XX_DEBUG_STALL_ON,
} GPTimerCC26XX_DebugMode;
@@ -268,28 +257,26 @@ typedef enum GPTimerCC26XX_DebugMode
* Definitions for controlling edges used for timer capture.
* Used in GPTimer edge-time and edge-count modes.
*/
typedef enum GPTimerCC26XX_Edge
{
typedef enum GPTimerCC26XX_Edge {
GPTimerCC26XX_POS_EDGE = GPT_CTL_TAEVENT_POS,
GPTimerCC26XX_NEG_EDGE = GPT_CTL_TAEVENT_NEG,
GPTimerCC26XX_BOTH_EDGES = GPT_CTL_TAEVENT_BOTH,
} GPTimerCC26XX_Edge;
/* Forward declaration of GPTimer configuration */
typedef const struct GPTimerCC26XX_Config GPTimerCC26XX_Config;
typedef const struct GPTimerCC26XX_Config GPTimerCC26XX_Config;
/* GPTimer handle is pointer to configuration structure */
typedef GPTimerCC26XX_Config * GPTimerCC26XX_Handle;
typedef GPTimerCC26XX_Config *GPTimerCC26XX_Handle;
/* Interrupt bit vector. See GPTimerCC26XX_Interrupt for available interrupts */
typedef uint16_t GPTimerCC26XX_IntMask;
typedef uint16_t GPTimerCC26XX_IntMask;
/* Timer value */
typedef uint32_t GPTimerCC26XX_Value;
typedef uint32_t GPTimerCC26XX_Value;
/* Function prototype for interrupt callbacks */
typedef void (*GPTimerCC26XX_HwiFxn) (GPTimerCC26XX_Handle handle, GPTimerCC26XX_IntMask interruptMask);
typedef void (*GPTimerCC26XX_HwiFxn)(GPTimerCC26XX_Handle handle, GPTimerCC26XX_IntMask interruptMask);
/*!
* @brief GPTimer26XX Hardware attributes
@@ -311,12 +298,11 @@ typedef void (*GPTimerCC26XX_HwiFxn) (GPTimerCC26XX_Handle handle, GPTimerCC26XX
* };
* @endcode
*/
typedef struct GPTimerCC26XX_HWAttrs
{
typedef struct GPTimerCC26XX_HWAttrs {
/*!< GPTimer peripheral base address */
uint32_t baseAddr;
/*! GPTimer peripheral interrupt vector */
uint8_t intNum;
uint8_t intNum;
/*! GPTimer peripheral's interrupt priority.
The CC26xx uses three of the priority bits,
meaning ~0 has the same effect as (7 << 5).
@@ -326,11 +312,11 @@ typedef struct GPTimerCC26XX_HWAttrs
HWI's with priority 0 ignore the HWI dispatcher to support zero-latency
interrupts, thus invalidating the critical sections in this driver.
*/
uint8_t intPriority;
uint8_t intPriority;
/*!< GPTimer peripheral's power manager ID */
uint8_t powerMngrId;
uint8_t powerMngrId;
/*! GPTimer half timer unit */
GPTimerCC26XX_Part timer;
GPTimerCC26XX_Part timer;
/*! PIN driver MUX */
GPTimerCC26XX_PinMux pinMux;
} GPTimerCC26XX_HWAttrs;
@@ -349,8 +335,7 @@ typedef struct GPTimerCC26XX_HWAttrs
* GPTimerCC26XX_Object gptimerCC26XXObjects[CC2650_GPTIMERCOUNT];
* @endcode
*/
typedef struct GPTimerCC26XX_Object
{
typedef struct GPTimerCC26XX_Object {
GPTimerCC26XX_Width width; /*!< Timer width configuration (16/32bit)*/
bool isOpen[GPT_PARTS_COUNT]; /*!< Object is opened flag */
Hwi_Struct hwi[GPT_PARTS_COUNT]; /*!< Hardware interrupt struct */
@@ -358,7 +343,6 @@ typedef struct GPTimerCC26XX_Object
volatile bool powerConstraint[GPT_PARTS_COUNT]; /*!< Standby power constraint flag */
} GPTimerCC26XX_Object;
/*!
* @brief GPTimer Global configuration
*
@@ -379,11 +363,10 @@ typedef struct GPTimerCC26XX_Object
* };
* @endcode
*/
struct GPTimerCC26XX_Config
{
GPTimerCC26XX_Object *object;
struct GPTimerCC26XX_Config {
GPTimerCC26XX_Object * object;
const GPTimerCC26XX_HWAttrs *hwAttrs;
GPTimerCC26XX_Part timerPart;
GPTimerCC26XX_Part timerPart;
};
/*!
@@ -394,14 +377,12 @@ struct GPTimerCC26XX_Config
*
* @sa GPTimerCC26XX_Params_init()
*/
typedef struct GPTimerCC26XX_Params
{
typedef struct GPTimerCC26XX_Params {
GPTimerCC26XX_Width width; /*!< Timer configuration (32/16-bit) */
GPTimerCC26XX_Mode mode; /*!< Timer mode */
GPTimerCC26XX_DebugMode debugStallMode; /*!< Timer debug stall mode */
} GPTimerCC26XX_Params;
/*!
* @brief Function to initialize the GPTimerCC26XX_Params struct to
* its default values
@@ -499,7 +480,6 @@ extern void GPTimerCC26XX_setLoadValue(GPTimerCC26XX_Handle handle, GPTimerCC26X
*/
extern void GPTimerCC26XX_setMatchValue(GPTimerCC26XX_Handle handle, GPTimerCC26XX_Value matchValue);
/*!
* @brief Function to set which input edge the GPTimer capture should
* use. Applies to edge-count and edge-time modes
@@ -546,7 +526,6 @@ extern GPTimerCC26XX_Value GPTimerCC26XX_getFreeRunValue(GPTimerCC26XX_Handle ha
*/
extern GPTimerCC26XX_Value GPTimerCC26XX_getValue(GPTimerCC26XX_Handle handle);
/*!
* @brief Function to register a CPU interrupt for a given timer handle and
* enable a set of timer interrupt sources. The interrupt to the CPU
@@ -648,12 +627,10 @@ extern void GPTimerCC26XX_configureDebugStall(GPTimerCC26XX_Handle handle, GPTim
*
* @sa GPTimerCC26XX_open
*/
static inline GPTimerCC26XX_PinMux GPTimerCC26XX_getPinMux(GPTimerCC26XX_Handle handle)
{
static inline GPTimerCC26XX_PinMux GPTimerCC26XX_getPinMux(GPTimerCC26XX_Handle handle) {
return handle->hwAttrs->pinMux;
}
#ifdef __cplusplus
}
#endif