save
This commit is contained in:
+3
@@ -32,4 +32,7 @@ static PIN_Config headstage_pin_configuration[] = { //
|
||||
headstage_pins_handle = PIN_open(&headstage_pins_state, headstage_pin_configuration); \
|
||||
} while (0)
|
||||
|
||||
#define headstage_pin_output(pin, value) PIN_setOutputValue(headstage_pins_handle, PIN_ID(pin), (value))
|
||||
#define headstage_pin_input(pin) PIN_getInputValue(PIN_ID(pin))
|
||||
|
||||
#endif // HEADSTAGE_PIN_H
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
#ifndef HEADSTAGE_TIMESTAMP_H
|
||||
#define HEADSTAGE_TIMESTAMP_H
|
||||
|
||||
#include <xdc/runtime/Timestamp.h>
|
||||
|
||||
#define headstage_time_stamp_us() (32*Timestamp_get32())
|
||||
#define headstage_time_stamp_ms() (Timestamp_get32()/32)
|
||||
|
||||
#endif // HEADSTAGE_TIMESTAMP_H
|
||||
+163
-115
@@ -8,9 +8,10 @@
|
||||
#define MAJOR_VERSION_NUMBER 0
|
||||
#define MINOR_VERSION_NUMBER 1
|
||||
|
||||
#include "headstage_pin.h"
|
||||
#include "headstage_gptimer.h"
|
||||
#include "headstage_pin.h"
|
||||
#include "headstage_spi.h"
|
||||
#include "headstage_timestamp.h"
|
||||
|
||||
/*============
|
||||
==== SPI ====
|
||||
@@ -51,6 +52,7 @@ static uint8_t spi_rxbuf[SPI_BUFFER_SIZE] = {0};
|
||||
#define ARM_MODE_RAMP 8
|
||||
// clang-format on
|
||||
|
||||
#define IS_REC_MODE(mode) (STI_MODE_DISABLE == (mode))
|
||||
#define IS_STI_MODE(mode) (STI_MODE_DISABLE < (mode) && (mode) <= STI_MODE_AWF)
|
||||
#define IS_ARM_MODE(mode) (ARM_MODE_RAMP == (mode))
|
||||
|
||||
@@ -74,7 +76,6 @@ static uint32_t sti_freq_table[] = {
|
||||
5000,
|
||||
5000, // 12
|
||||
5000, // 13
|
||||
|
||||
5000, // 14
|
||||
5000, // 15
|
||||
};
|
||||
@@ -150,8 +151,14 @@ struct HEADSTAGE_PARAMETER_TABLE {
|
||||
* amplifier reset
|
||||
*/
|
||||
bool amp_rst;
|
||||
|
||||
int8_t channel_pointer;
|
||||
|
||||
uint8_t not_buf_offset;
|
||||
} INSTRUCTION = {0};
|
||||
|
||||
#define actual_frequency() ((INSTRUCTION.frequency_mode == FREQ_MODE_INDEX) ? (adc_clock_table[INSTRUCTION.frequency]) : (INSTRUCTION.frequency))
|
||||
|
||||
/*=============================
|
||||
==== function declaration ====
|
||||
============================*/
|
||||
@@ -188,6 +195,14 @@ static void headstage_tni_event() {
|
||||
==========================*/
|
||||
|
||||
static void headstage_tni_init() {
|
||||
// XXX spi parameter
|
||||
headstage_spi_open();
|
||||
|
||||
// XXX gptimer parameter
|
||||
headstage_gptimer_open();
|
||||
|
||||
// XXX pin configuration
|
||||
headstage_pin_open();
|
||||
}
|
||||
|
||||
static void headstage_update_ris_instruction(uint8_t *instruction) {
|
||||
@@ -339,6 +354,28 @@ static void headstage_update_ris_instruction(uint8_t *instruction) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// update gpimter
|
||||
uint32_t frequency = 0;
|
||||
if (INSTRUCTION.frequency_mode == FREQ_MODE_INDEX) {
|
||||
if (IS_REC_MODE(INSTRUCTION.mode) || IS_ARM_MODE(INSTRUCTION.mode)) {
|
||||
// recording mode
|
||||
frequency = adc_clock_table[INSTRUCTION.frequency];
|
||||
|
||||
} else if (IS_STI_MODE(INSTRUCTION.mode)) {
|
||||
// stimulation mode
|
||||
frequency = sti_freq_table[INSTRUCTION.frequency];
|
||||
}
|
||||
} else {
|
||||
frequency = INSTRUCTION.frequency;
|
||||
}
|
||||
|
||||
if (frequency > 0) {
|
||||
headstage_gptimer_set_frequency(frequency);
|
||||
}
|
||||
|
||||
// update instruction buffer
|
||||
update_ins_buffer();
|
||||
}
|
||||
|
||||
static void headstage_update_vis_instruction(uint8_t vis_oper) {
|
||||
@@ -346,185 +383,149 @@ static void headstage_update_vis_instruction(uint8_t vis_oper) {
|
||||
// uni system trigger
|
||||
case VIS_STI:
|
||||
INSTRUCTION.flag_start = TRUE;
|
||||
headstage_gptimer_start();
|
||||
break;
|
||||
|
||||
// reset
|
||||
case VIS_RST:
|
||||
// stop gptimer
|
||||
headstage_gptimer_stop();
|
||||
|
||||
// reset. reset all variable
|
||||
channel_pointer = -1;
|
||||
not_buf_offset = NOT_BUF_OFFSET_INIT;
|
||||
INSTRUCTION.channel_pointer = -1;
|
||||
not_buf_offset = NOT_BUF_OFFSET_INIT;
|
||||
memset(&INSTRUCTION, 0, sizeof(struct HEADSTAGE_PARAMETER_TABLE));
|
||||
memset(spi_txbuf, 0, SPI_BUFFER_SIZE);
|
||||
break;
|
||||
|
||||
// interrupt
|
||||
case VIS_INT:
|
||||
// stop gptimer
|
||||
headstage_gptimer_stop();
|
||||
|
||||
// stop. reset channel table
|
||||
channel_pointer = -1;
|
||||
not_buf_offset = NOT_BUF_OFFSET_INIT;
|
||||
INSTRUCTION.channel_pointer = -1;
|
||||
not_buf_offset = NOT_BUF_OFFSET_INIT;
|
||||
memset(&INSTRUCTION.channel_table, 0, REC_CHANNEL_COUNT);
|
||||
memset(spi_txbuf, 0, SPI_BUFFER_SIZE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define NOT_BUF_OFFSET_INIT 8
|
||||
|
||||
static void send_notify() {
|
||||
// set notify information
|
||||
not_buf[0] = INSTRUCTION.chip_id; // chip id
|
||||
not_buf[1] = not_buf_offset - 2; // data length
|
||||
static uint32_t not_buf_offset = 0;
|
||||
static uint32_t not_time_stamp = 0;
|
||||
|
||||
not_final_stamp = 32*Timestamp_get32();
|
||||
static void headstage_set_time_stamp() {
|
||||
not_time_stamp = headstage_time_stamp_us();
|
||||
|
||||
uint16_t time_delta = (not_final_stamp - not_time_stamp) & 0xffff;
|
||||
not_buf[2] = not_time_stamp & 0xFF;
|
||||
not_buf[3] = (not_time_stamp >> 8) & 0xFF;
|
||||
not_buf[4] = (not_time_stamp >> 16) & 0xFF;
|
||||
not_buf[5] = (not_time_stamp >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
not_buf[6] = time_delta & 0xff ;
|
||||
not_buf[7] = (time_delta >> 8) & 0xff;
|
||||
static void headstage_set_time_delta() {
|
||||
uint32_t current = headstage_time_stamp_us();
|
||||
uint32_t time_delta = (current - not_time_stamp) & 0xFFFF;
|
||||
|
||||
headstage_noti();
|
||||
not_buf[6] = time_delta & 0xFF;
|
||||
not_buf[7] = (time_delta >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
// freq < 7 => sampling rate = 1k
|
||||
// if(INSTRUCTION.frequency < 7)
|
||||
// delta_zero();
|
||||
static void headstage_prepare_notify() {
|
||||
not_buf[0] = CHIP_ID; // chip id
|
||||
not_buf[1] = not_buf_offset - 2; // data length
|
||||
|
||||
// set value to trigger notify. not_buf -> characteristic 4
|
||||
headstage_set_time_delta();
|
||||
|
||||
// reset counter
|
||||
not_buf_offset = NOT_BUF_OFFSET_INIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* move data to not_buf. If not_buf is full, send notify.
|
||||
*/
|
||||
static void collect_data(uint8_t *buf) {
|
||||
static void headstage_collect_data(uint8_t *dat_buf) {
|
||||
uint8 flag;
|
||||
|
||||
// checking data header
|
||||
if ((buf[0] & 0b11110000) == 0b10110000) {
|
||||
if ((dat_buf[0] & 0xF0) == 0xB0) {
|
||||
// valid value
|
||||
flag = 0b0000;
|
||||
flag = 0x00;
|
||||
} else {
|
||||
// invalid value
|
||||
flag = 0b0011;
|
||||
flag = 0x03;
|
||||
}
|
||||
|
||||
// change data buffer content
|
||||
// add channel and flag information
|
||||
buf[0] = (buf[0] & 0b00001111) | (display_ch << 4);
|
||||
buf[1] = (buf[1] & 0b11111100) | flag;
|
||||
dat_buf[0] = (dat_buf[0] & 0x0F) | (display_ch << 4);
|
||||
dat_buf[1] = (dat_buf[1] & 0xFC) | flag;
|
||||
|
||||
if (not_buf_offset == NOT_BUF_OFFSET_INIT) {
|
||||
headstage_set_time_stamp();
|
||||
}
|
||||
|
||||
// data buffer -> not_buf
|
||||
memcpy(not_buf + not_buf_offset, buf, 2);
|
||||
not_buf_offset += 2;
|
||||
|
||||
// check buffer full or not
|
||||
// check whether has more place to append data into notify buffer
|
||||
if (not_buf_offset >= BLE_DAT_BUFF_SIZE) {
|
||||
send_notify();
|
||||
headstage_prepare_notify();
|
||||
headstage_send_notify();
|
||||
}
|
||||
|
||||
if (not_buf_offset == NOT_BUF_OFFSET_INIT) {
|
||||
// this time bluetooth transmit information
|
||||
not_time_stamp = (Timestamp_get32())/32; // its unit 32us * timestamp
|
||||
// 32 khz timer
|
||||
|
||||
// add cpu time information into notify buffer
|
||||
|
||||
not_buf[2] = not_time_stamp & 0xff;
|
||||
not_buf[3] = (not_time_stamp >> 8) & 0xff;
|
||||
not_buf[4] = (not_time_stamp >> 16) & 0xff;
|
||||
not_buf[5] = (not_time_stamp >> 24) & 0xff;
|
||||
}
|
||||
|
||||
// data buffer -> not_buf
|
||||
memcpy(not_buf + not_buf_offset, buf, 2);
|
||||
not_buf_offset += 2;
|
||||
}
|
||||
|
||||
static void collect_low_freq_data(uint8_t *buf) {
|
||||
uint8 flag;
|
||||
|
||||
// checking data header
|
||||
if ((buf[0] & 0b11110000) == 0b10110000) {
|
||||
// valid value
|
||||
flag = 0b0000;
|
||||
} else {
|
||||
// invalid value
|
||||
flag = 0b0011;
|
||||
}
|
||||
|
||||
// change data buffer content
|
||||
// add channel and flag information
|
||||
buf[0] = (buf[0] & 0b00001111) | (display_ch << 4);
|
||||
buf[1] = (buf[1] & 0b11111100) | flag;
|
||||
|
||||
// check buffer full or not
|
||||
// check whether has more place to append data into notify buffer
|
||||
if (not_buf_offset >= NOT_BUF_OFFSET_INIT + 2) {
|
||||
send_notify();
|
||||
}
|
||||
|
||||
if (not_buf_offset == NOT_BUF_OFFSET_INIT) {
|
||||
// this time bluetooth transmit information
|
||||
not_time_stamp = (Timestamp_get32());
|
||||
// 32 khz timer
|
||||
|
||||
// add cpu time information into notify buffer
|
||||
|
||||
not_buf[2] = not_time_stamp & 0xff;
|
||||
not_buf[3] = (not_time_stamp >> 8) & 0xff;
|
||||
not_buf[4] = (not_time_stamp >> 16) & 0xff;
|
||||
not_buf[5] = (not_time_stamp >> 24) & 0xff;
|
||||
}
|
||||
|
||||
// data buffer -> not_buf
|
||||
memcpy(not_buf + not_buf_offset, buf, 2);
|
||||
not_buf_offset += 2;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* change the recording clock bit in the instruction buffer.
|
||||
*/
|
||||
static void update_ins_rec_clock(uint8_t *buf, bool adc_clock_signal) {
|
||||
buf[3] = (buf[3] & 0b11110000) | ((adc_clock_signal) ? 0b1000 : 0);
|
||||
static void update_ins_rec_clock(uint8_t *ins_buf, bool adc_clock_signal) {
|
||||
ins_buf[3] = (ins_buf[3] & 0b11110000) | ((adc_clock_signal) ? 0b1000 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* change the recording channel bit in the instruction buffer.
|
||||
*/
|
||||
static void update_ins_rec_channel(uint8_t *buf, uint8 channel) {
|
||||
buf[1] = (buf[1] & 0b00001111) | (encode_channel(channel) << 4);
|
||||
static void update_ins_rec_channel(uint8_t *ins_buf, uint8 channel) {
|
||||
ins_buf[1] = (ins_buf[1] & 0b00001111) | (_B_flip4(channel) << 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* change the stimulation enable bit in the instruction buffer.
|
||||
*/
|
||||
static void update_ins_sti_enable(uint8_t *buf, bool enable) {
|
||||
buf[1] = (buf[1] & 0b11111101) | ((enable) ? 0b10 : 0);
|
||||
static void update_ins_sti_enable(uint8_t *ins_buf, bool enable) {
|
||||
ins_buf[1] = (ins_buf[1] & 0b11111101) | ((enable) ? 0b10 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* change the stimulating channel bit in the instruction buffer.
|
||||
*/
|
||||
static void update_ins_sti_channel(uint8_t *buf, uint8 sti_chp, uint8 sti_chn) {
|
||||
buf[2] = (buf[2] & 0b11110000) | encode_channel(sti_chp);
|
||||
buf[3] = (buf[3] & 0b00001111) | (encode_channel(sti_chn) << 4);
|
||||
static void update_ins_sti_channel(uint8_t *ins_buf, uint8 sti_chp, uint8 sti_chn) {
|
||||
ins_buf[2] = (ins_buf[2] & 0b11110000) | (_B_flip4(sti_chp));
|
||||
ins_buf[3] = (ins_buf[3] & 0b00001111) | (_B_flip4(sti_chn) << 4);
|
||||
}
|
||||
|
||||
static void update_ins_buffer() {
|
||||
uint8 header = 0b10100000;
|
||||
uint8 amp_gain = (swap_gain(INSTRUCTION.amp_gain) & 0b11) << 3;
|
||||
uint8 amp_lbf = swap_lbf(INSTRUCTION.amp_low_band_freq) & 0b111;
|
||||
uint8 amp_gain = (_B_flip2(INSTRUCTION.amp_gain) & 0b11) << 3;
|
||||
uint8 amp_lbf = _B_flip3(INSTRUCTION.amp_low_band_freq) & 0b111;
|
||||
uint8 channel = 0; // should be call update_ins_channel to modify this value
|
||||
uint8 chopper = (INSTRUCTION.chopper) ? 0b00001000 : 0;
|
||||
uint8 fast_settle = (INSTRUCTION.fast_settle) ? 0b00000100 : 0;
|
||||
uint8 sti_enable = (INSTRUCTION.work_mode != STI_MODE_DISABLE) ? 0b00000010 : 0;
|
||||
uint8 sti_volt_l = (swap_sti_volt(INSTRUCTION.sti_volt) & 0b10000) >> 4;
|
||||
uint8 sti_volt_h = (swap_sti_volt(INSTRUCTION.sti_volt) & 0b01111) << 4;
|
||||
uint8 sti_enable = (INSTRUCTION.mode != STI_MODE_DISABLE) ? 0b00000010 : 0;
|
||||
uint8 sti_volt = _B_flip5(INSTRUCTION.sti_volt);
|
||||
uint8 sti_volt_l = (sti_volt & 0b10000) >> 4;
|
||||
uint8 sti_volt_h = (sti_volt & 0b01111) << 4;
|
||||
uint8 sti_chp = INSTRUCTION.sti_channel_pmos & 0b1111;
|
||||
uint8 sti_chn = (INSTRUCTION.sti_channel_nmos & 0b1111) << 4;
|
||||
uint8 clk_signal = 0; // should be call update_ins_clock to modify this value
|
||||
uint8 clk_signal = 0; // updated by update_ins_rec_clock to modify this value
|
||||
|
||||
if(amp_rst){
|
||||
amp_rst = 0;
|
||||
fast_settle = 0b0001000;
|
||||
if (INSTRUCTION.amp_rst) {
|
||||
INSTRUCTION.amp_rst = 0;
|
||||
fast_settle = 0b0001000;
|
||||
}
|
||||
|
||||
spi_txbuf[0] = header | amp_gain | amp_lbf;
|
||||
@@ -533,28 +534,32 @@ static void update_ins_buffer() {
|
||||
spi_txbuf[3] = sti_chn | clk_signal;
|
||||
}
|
||||
|
||||
/**
|
||||
* find next enable channel
|
||||
*/
|
||||
static bool next_active_channel() {
|
||||
// find next enable channel
|
||||
channel_pointer += 1;
|
||||
while (channel_pointer < CHANNEL_COUNT && !channel_table[channel_pointer]) {
|
||||
channel_pointer++;
|
||||
int8_t cp = INSTRUCTION.channel_pointer + 1;
|
||||
|
||||
while (cp < REC_CHANNEL_COUNT && !INSTRUCTION.channel_table[cp]) {
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (channel_pointer >= CHANNEL_COUNT) {
|
||||
if (cp >= REC_CHANNEL_COUNT) {
|
||||
// channel to to the end of the channel_table, set to the beginning and re-search enable channel.
|
||||
channel_pointer = 0;
|
||||
while (channel_pointer < CHANNEL_COUNT && !channel_table[channel_pointer]) {
|
||||
channel_pointer++;
|
||||
cp = 0;
|
||||
while (cp < CHANNEL_COUNT && !channel_table[cp]) {
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (channel_pointer >= CHANNEL_COUNT) {
|
||||
if (channel_pointer >= REC_CHANNEL_COUNT) {
|
||||
// no channel enable, return directly
|
||||
|
||||
channel_pointer = -1;
|
||||
INSTRUCTION.channel_pointer = -1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
INSTRUCTION.channel_pointer = cp;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -604,7 +609,7 @@ static bool update_ins_rec_buffer() {
|
||||
* @param: buf: pointer of the SPI buffer.
|
||||
*/
|
||||
static void update_ins_sti_buffer() {
|
||||
switch (INSTRUCTION.work_mode) {
|
||||
switch (INSTRUCTION.mode) {
|
||||
case STI_MODE_POS:
|
||||
case STI_MODE_NEG:
|
||||
// copy [4:7]
|
||||
@@ -668,5 +673,48 @@ static void update_ins_sti_buffer() {
|
||||
}
|
||||
}
|
||||
|
||||
static void headstage_tni_periodic() {
|
||||
if (!INSTRUCTION.flag_start) return;
|
||||
|
||||
if (IS_REC_MODE(INSTRUCTION.mode)) {
|
||||
// recording mode
|
||||
|
||||
if (update_ins_rec_buffer()) {
|
||||
headstage_pin_output(P2S_RST, 1); // DBS_P2S turn on
|
||||
headstage_spi_transaction(SPI_BUFFER_SIZE, spi_txbuf, spi_rxbuf);
|
||||
headstage_pin_output(P2S_RST, 0); // DBS_P2S turn off
|
||||
}
|
||||
|
||||
goto collect_data;
|
||||
} else if (IS_ARM_MODE(INSTRUCTION.mode)) {
|
||||
// artifact recording mode
|
||||
|
||||
if (update_ins_rec_buffer()) {
|
||||
// create_ramp(spi_rxbuf);
|
||||
}
|
||||
|
||||
goto collect_data;
|
||||
} else if (IS_STI_MODE(INSTRUCTION.mode)) {
|
||||
// stimulation mode
|
||||
update_ins_sti_buffer();
|
||||
headstage_spi_transaction(SPI_BUFFER_SIZE, spi_txbuf, NULL);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
collect_data:
|
||||
|
||||
if (!INSTRUCTION.adc_clock_signal) {
|
||||
headstage_collect_data(spi_rxbuf);
|
||||
headstage_pin_output(S2P_RST, 1);
|
||||
|
||||
if (actual_frequency() < 1000) {
|
||||
// low sampling rate data format check
|
||||
headstage_prepare_notify();
|
||||
headstage_send_notify();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#endif // HEADSTAGE_TNI_H
|
||||
Reference in New Issue
Block a user