This commit is contained in:
Ta-Shun Su
2019-05-07 14:57:52 +08:00
parent a04c82b07d
commit bf2b1b1b98
3 changed files with 175 additions and 115 deletions
@@ -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
@@ -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
@@ -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