diff --git a/example/thunderscope_test.cpp b/example/thunderscope_test.cpp index 19ea970..37d206b 100644 --- a/example/thunderscope_test.cpp +++ b/example/thunderscope_test.cpp @@ -326,7 +326,8 @@ static void test_io(file_t fd, bool isBeta) } static void test_capture(file_t fd, uint32_t idx, uint8_t channelBitmap, uint16_t bandwidth, - uint32_t volt_scale_uV, int32_t offset_uV, uint8_t ac_couple, uint8_t term, bool watch_bitslip, bool is12bit, bool inRefClk, bool outRefClk, uint32_t refclkFreq) + uint32_t volt_scale_uV, int32_t offset_uV, uint8_t ac_couple, uint8_t term, bool watch_bitslip, + bool is12bit, bool is14bit, bool inRefClk, bool outRefClk, uint32_t refclkFreq) { uint8_t numChan = 0; tsHandle_t tsHdl = thunderscopeOpen(idx, false); @@ -375,11 +376,16 @@ static void test_capture(file_t fd, uint32_t idx, uint8_t channelBitmap, uint16_ if(is12bit) { sampleRate = 660000000; - thunderscopeSampleModeSet(tsHdl, sampleRate/numChan, 4096); + thunderscopeSampleModeSet(tsHdl, sampleRate/numChan, TS_12_BIT_MSB); + } + else if(is14bit) + { + sampleRate = 125000000; + thunderscopeSampleModeSet(tsHdl, sampleRate, TS_14_BIT); } else { - thunderscopeSampleModeSet(tsHdl, sampleRate/numChan, 256); + thunderscopeSampleModeSet(tsHdl, sampleRate/numChan, TS_8_BIT); } printf("- Checking HMCAD1520 Sample Rate..."); @@ -706,7 +712,7 @@ int main(int argc, char** argv) uint8_t ac_couple = 0; uint8_t term = 0; bool bitslip = false; - bool mode12bit = false; + bool mode12bit = false, mode14bit = false; bool refInClk = false; bool refOutClk = false; uint32_t refclkFreq = 0; @@ -782,6 +788,10 @@ int main(int argc, char** argv) mode12bit = true; argCount++; break; + case 'p': + mode14bit = true; + argCount++; + break; case '?': fprintf(stderr, "%s: %s\n", argv[0], options.errmsg); print_help(); @@ -918,7 +928,7 @@ int main(int argc, char** argv) // Setup Channel, record samples to buffer, save buffer to file else if(0 == strcmp(arg, "capture")) { - test_capture(fd, idx, channelBitmap, bandwidth, volt_scale_uV, offset_uV, ac_couple, term, bitslip, mode12bit, refInClk, refOutClk, refclkFreq); + test_capture(fd, idx, channelBitmap, bandwidth, volt_scale_uV, offset_uV, ac_couple, term, bitslip, mode12bit, mode14bit, refInClk, refOutClk, refclkFreq); } // Flash test else if(0 == strcmp(arg, "flash")) diff --git a/include/thunderscope.h b/include/thunderscope.h index 2296a06..40086f2 100644 --- a/include/thunderscope.h +++ b/include/thunderscope.h @@ -91,10 +91,10 @@ int32_t thunderscopeStatusGet(tsHandle_t ts, tsScopeState_t* conf); * * @param ts Handle to the Thunderscope device * @param rate Sample Rate to collect (samples per second) - * @param resolution Resolution to sample at. 256 or 4096 + * @param mode Sample Capture Mode * @return int32_t TS_STATUS_OK if the Thunderscope was configured */ -int32_t thunderscopeSampleModeSet(tsHandle_t ts, uint32_t rate, uint32_t resolution); +int32_t thunderscopeSampleModeSet(tsHandle_t ts, uint32_t rate, tsSampleFormat_t mode); /** * @brief Set the approximate rate at which interrupts will fire diff --git a/include/ts_common.h b/include/ts_common.h index d945310..815b864 100644 --- a/include/ts_common.h +++ b/include/ts_common.h @@ -61,6 +61,14 @@ typedef enum tsChannelTerm_e TS_TERM_50 = 1, } tsChannelTerm_t; +typedef enum tsSampleFormat_e +{ + TS_8_BIT = 0, + TS_12_BIT_LSB, + TS_12_BIT_MSB, + TS_14_BIT +}tsSampleFormat_t; + typedef enum tsRefClockMode_e { TS_REFCLK_NONE = 0, diff --git a/src/adc.c b/src/adc.c index 1f5bd64..7c3bc47 100644 --- a/src/adc.c +++ b/src/adc.c @@ -16,8 +16,9 @@ #include "ts_calibration.h" -#define TS_ADC_DATA_FRAMING_8BIT (0) -#define TS_ADC_DATA_FRAMING_12BIT (1 << CSR_ADC_HMCAD1520_SAMPLE_BITS_DATA_WIDTH_OFFSET); +#define TS_ADC_DATA_FRAMING_8BIT (0) +#define TS_ADC_DATA_FRAMING_12BIT_MSB (1 << CSR_ADC_HMCAD1520_SAMPLE_BITS_DATA_WIDTH_OFFSET); +#define TS_ADC_DATA_FRAMING_12BIT_LSB (2 << CSR_ADC_HMCAD1520_SAMPLE_BITS_DATA_WIDTH_OFFSET); typedef enum adc_shuffle_e { @@ -27,6 +28,7 @@ typedef enum adc_shuffle_e ADC_12B_SHUFFLE_1CH = 3, ADC_12B_SHUFFLE_2CH = 4, ADC_12B_SHUFFLE_4CH = 5, + ADC_DUAL_8B_SHUFFLE_4CH = 6, } adc_shuffle_t; @@ -156,8 +158,13 @@ int32_t ts_adc_update_channels(ts_adc_t* adc) } else { - - if(activeCount == 1) + if(adc->adcDev.width == HMCAD15_14_BIT) + { + //Set Quad Channel, Dual-8 + adc->adcDev.mode = HMCAD15_PREC_QUAD_CHANNEL; + shuffleMode = ADC_DUAL_8B_SHUFFLE_4CH; + } + else if(activeCount == 1) { adc->adcDev.mode = HMCAD15_SINGLE_CHANNEL; shuffleMode = ((adc->adcDev.width == HMCAD15_8_BIT) ? ADC_8B_SHUFFLE_1CH : ADC_12B_SHUFFLE_1CH); @@ -212,7 +219,7 @@ int32_t ts_adc_run(ts_adc_t* adc, uint8_t en) return TS_STATUS_OK; } -int32_t ts_adc_set_sample_mode(ts_adc_t* adc, uint32_t sample_rate, uint32_t resolution) +int32_t ts_adc_set_sample_mode(ts_adc_t* adc, uint32_t sample_rate, tsSampleFormat_t mode) { if(!adc) { @@ -220,15 +227,20 @@ int32_t ts_adc_set_sample_mode(ts_adc_t* adc, uint32_t sample_rate, uint32_t res } hmcad15xxDataWidth_t data_mode = HMCAD15_8_BIT; uint32_t sample_bits = TS_ADC_DATA_FRAMING_8BIT; - if(resolution == 4096) + if(mode == TS_12_BIT_LSB) { data_mode = HMCAD15_12_BIT; - sample_bits = TS_ADC_DATA_FRAMING_12BIT; + sample_bits = TS_ADC_DATA_FRAMING_12BIT_LSB; } - else if(resolution == 16384) + else if(mode == TS_12_BIT_MSB) + { + data_mode = HMCAD15_12_BIT; + sample_bits = TS_ADC_DATA_FRAMING_12BIT_MSB; + } + else if(mode == TS_14_BIT) { - data_mode = HMCAD15_14_BIT; //Precision mode uses Dual-8 LVDS + data_mode = HMCAD15_14_BIT; sample_bits = TS_ADC_DATA_FRAMING_8BIT; } @@ -241,7 +253,7 @@ int32_t ts_adc_set_sample_mode(ts_adc_t* adc, uint32_t sample_rate, uint32_t res } else { - LOG_ERROR("Failed to set the ADC Sample Mode %d/%d", sample_rate, resolution); + LOG_ERROR("Failed to set the ADC Sample Mode %d/%d", sample_rate, mode); return TS_STATUS_ERROR; } } diff --git a/src/adc.h b/src/adc.h index ef7cec6..b52ecf9 100644 --- a/src/adc.h +++ b/src/adc.h @@ -98,10 +98,10 @@ int32_t ts_adc_run(ts_adc_t* adc, uint8_t en); * * @param adc Pointer to a ADC instance * @param sample_rate Rate of the ADC Sample clock (Hz) - * @param resolution Resolution mode setting for the ADC. + * @param mode Resolution mode setting for the ADC. * @return int32_t TS_STATUS_OK if the mode was applied successfully */ -int32_t ts_adc_set_sample_mode(ts_adc_t* adc, uint32_t sample_rate, uint32_t resolution); +int32_t ts_adc_set_sample_mode(ts_adc_t* adc, uint32_t sample_rate, tsSampleFormat_t mode); /** * @brief Set the calibration on the ADC diff --git a/src/hmcad15xx.c b/src/hmcad15xx.c index 055627f..dd61073 100644 --- a/src/hmcad15xx.c +++ b/src/hmcad15xx.c @@ -107,6 +107,7 @@ int32_t hmcad15xx_power_mode(hmcad15xxADC_t* adc, hmcad15xxPower_t power) HMCAD15_DUAL_CH_1_SLP : 0; break; case HMCAD15_QUAD_CHANNEL: + case HMCAD15_PREC_QUAD_CHANNEL: data |= adc->channelCfg[0].active == 0 ? HMCAD15_QUAD_CH_0_SLP : 0; data |= adc->channelCfg[1].active == 0 ? @@ -264,7 +265,7 @@ int32_t hmcad15xx_set_sample_mode(hmcad15xxADC_t* adc, uint32_t sample_rate, hmc if(((adc->mode == HMCAD15_SINGLE_CHANNEL) && (sample_rate < HMCAD15_SINGLE_LOW_CLK_THRESHOLD)) || ((adc->mode == HMCAD15_DUAL_CHANNEL) && (sample_rate < HMCAD15_DUAL_LOW_CLK_THRESHOLD)) || ((adc->mode == HMCAD15_QUAD_CHANNEL) && (sample_rate < HMCAD15_QUAD_LOW_CLK_THRESHOLD)) || - ((adc->mode == HMCAD15_14BIT_QUAD_CHANNEL) && (sample_rate < HMCAD15_PREC_LOW_CLK_THRESHOLD))) + ((adc->mode == HMCAD15_PREC_QUAD_CHANNEL) && (sample_rate < HMCAD15_PREC_LOW_CLK_THRESHOLD))) { adc->low_clk = 1; } @@ -340,7 +341,7 @@ static void hmcad15xxApplySampleMode(hmcad15xxADC_t* adc) data = HMCAD15_SAMPLE_MODE_SET(adc->mode) | HMCAD15_CLK_DIV_SET(adc->clockDiv); break; - case HMCAD15_14BIT_QUAD_CHANNEL: + case HMCAD15_PREC_QUAD_CHANNEL: adc->clockDiv = HMCAD15_CLK_DIV_1; data = HMCAD15_SAMPLE_MODE_SET(adc->mode) | HMCAD15_SAMPLE_MODE_PREC | @@ -372,6 +373,7 @@ static void hmcad15xxApplyChannelMap(hmcad15xxADC_t* adc) HMCAD15_CH_INVERT_D2(adc->channelCfg[1].invert); break; case HMCAD15_QUAD_CHANNEL: + case HMCAD15_PREC_QUAD_CHANNEL: in12 = HMCAD15_SEL_CH_1(adc->channelCfg[0].input); in12 |= HMCAD15_SEL_CH_2(adc->channelCfg[1].input); in34 = HMCAD15_SEL_CH_3(adc->channelCfg[2].input); @@ -407,6 +409,7 @@ static void hmcad15xxApplyChannelGain(hmcad15xxADC_t* adc) hmcad15xxRegWrite(adc, HMCAD15_REG_COARSE_GAIN_2, cgain); break; case HMCAD15_QUAD_CHANNEL: + case HMCAD15_PREC_QUAD_CHANNEL: cgain = HMCAD15_CGAIN_Q1(adc->channelCfg[0].coarse); cgain |= HMCAD15_CGAIN_Q2(adc->channelCfg[1].coarse); cgain |= HMCAD15_CGAIN_Q3(adc->channelCfg[2].coarse); diff --git a/src/hmcad15xx.h b/src/hmcad15xx.h index 9e8dc0e..2676c7d 100644 --- a/src/hmcad15xx.h +++ b/src/hmcad15xx.h @@ -176,7 +176,7 @@ typedef enum hmcad15xxMode_e HMCAD15_SINGLE_CHANNEL = 1, HMCAD15_DUAL_CHANNEL = 2, HMCAD15_QUAD_CHANNEL = 4, - HMCAD15_14BIT_QUAD_CHANNEL = 8 + HMCAD15_PREC_QUAD_CHANNEL = 8 } hmcad15xxMode_t; typedef enum hmcad15xxDataWidth_e diff --git a/src/thunderscope.c b/src/thunderscope.c index 1471c42..e69f27d 100644 --- a/src/thunderscope.c +++ b/src/thunderscope.c @@ -243,17 +243,17 @@ int32_t thunderscopeStatusGet(tsHandle_t ts, tsScopeState_t* state) return TS_STATUS_OK; } -int32_t thunderscopeSampleModeSet(tsHandle_t ts, uint32_t rate, uint32_t resolution) +int32_t thunderscopeSampleModeSet(tsHandle_t ts, uint32_t rate, tsSampleFormat_t mode) { ts_inst_t* pInst = (ts_inst_t*)ts; if(pInst && pInst->initialized) { - int32_t status = ts_channel_sample_rate_set(pInst->pChannel, rate, resolution); + int32_t status = ts_channel_sample_rate_set(pInst->pChannel, rate, mode); if(status == TS_STATUS_OK) { //Target 100Hz interrupt rate - pInst->samples.interrupt_rate = 1 + ((((resolution == 256) ? rate : 2*rate) / + pInst->samples.interrupt_rate = 1 + ((((mode == TS_8_BIT) ? rate : 2*rate) / (DMA_BUFFER_SIZE)) / pInst->interrupt_rate); LOG_DEBUG("DMA Interrupt Rate is 1/%d MB", pInst->samples.interrupt_rate); diff --git a/src/ts_channel.c b/src/ts_channel.c index 6f5029f..de96293 100644 --- a/src/ts_channel.c +++ b/src/ts_channel.c @@ -50,6 +50,7 @@ typedef struct ts_channel_s { gpio_t afe_power; gpio_t acq_power; file_t ctrl_handle; + tsSampleFormat_t sampleMode; tsScopeState_t status; } ts_channel_t; @@ -495,7 +496,7 @@ static int32_t ts_channel_update_params(ts_channel_t* pTsHdl, uint32_t chanIdx, } //Update Sample Rate - retVal = ts_channel_sample_rate_set((tsChannelHdl_t)pTsHdl, pTsHdl->status.adc_sample_rate, pTsHdl->status.adc_sample_resolution); + retVal = ts_channel_sample_rate_set((tsChannelHdl_t)pTsHdl, pTsHdl->status.adc_sample_rate, pTsHdl->sampleMode); } return retVal; @@ -550,7 +551,7 @@ tsScopeState_t ts_channel_scope_status(tsChannelHdl_t tsChannels) return pTsHdl->status; } -int32_t ts_channel_sample_rate_set(tsChannelHdl_t tsChannels, uint32_t rate, uint32_t resolution) +int32_t ts_channel_sample_rate_set(tsChannelHdl_t tsChannels, uint32_t rate, tsSampleFormat_t mode) { if(tsChannels == NULL) { @@ -560,16 +561,34 @@ int32_t ts_channel_sample_rate_set(tsChannelHdl_t tsChannels, uint32_t rate, uin uint64_t actual_rate = 0; uint64_t max_rate = 0; - if(resolution == 256) + + switch(mode) + { + case TS_8_BIT: { max_rate = TS_MAX_8BIT_SAMPLE_RATE; + ts->status.adc_sample_resolution = 256; + break; } - else if(resolution == 4096) + case TS_12_BIT_LSB: { max_rate = TS_MAX_12BIT_SAMPLE_RATE; + ts->status.adc_sample_resolution = 4096; + break; } - else + case TS_12_BIT_MSB: + { + max_rate = TS_MAX_12BIT_SAMPLE_RATE; + ts->status.adc_sample_resolution = 65536; + break; + } + case TS_14_BIT: { + max_rate = TS_MAX_14BIT_SAMPLE_RATE; + ts->status.adc_sample_resolution = 65536; + break; + } + default: return TS_INVALID_PARAM; } @@ -578,7 +597,10 @@ int32_t ts_channel_sample_rate_set(tsChannelHdl_t tsChannels, uint32_t rate, uin return TS_INVALID_PARAM; } - if(ts->adc.adcDev.mode == HMCAD15_SINGLE_CHANNEL) + ts->sampleMode = mode; + + // Use 1:1 rate for precision mode (14_bit) + if((ts->adc.adcDev.mode == HMCAD15_SINGLE_CHANNEL) || (ts->sampleMode == TS_14_BIT)) { actual_rate = rate; } @@ -625,10 +647,9 @@ int32_t ts_channel_sample_rate_set(tsChannelHdl_t tsChannels, uint32_t rate, uin } ts->status.adc_sample_rate = rate; - ts->status.adc_sample_resolution = resolution; - ts->status.adc_sample_bits = resolution == 256 ? 8 : 16; + ts->status.adc_sample_bits = (mode == TS_8_BIT) ? 8 : 16; - ts_adc_set_sample_mode(&ts->adc, rate, resolution); + ts_adc_set_sample_mode(&ts->adc, rate, mode); ts_adc_run(&ts->adc, ts->status.adc_state); return TS_STATUS_OK; diff --git a/src/ts_channel.h b/src/ts_channel.h index 32cc0d0..6575d91 100644 --- a/src/ts_channel.h +++ b/src/ts_channel.h @@ -81,10 +81,10 @@ tsScopeState_t ts_channel_scope_status(tsChannelHdl_t tsChannels); * * @param tsChannels Thunderscope Channel handle * @param rate Samples per Second - * @param resolution Number of bits in each sample. Valid values are 2^8 (256) and 2^12 (4096). + * @param mode Sample Mode to set the resolution of each sample. * @return int32_t TS_STATUS_OK on success, else TS_STATUS_ERROR */ -int32_t ts_channel_sample_rate_set(tsChannelHdl_t tsChannels, uint32_t rate, uint32_t resolution); +int32_t ts_channel_sample_rate_set(tsChannelHdl_t tsChannels, uint32_t rate, tsSampleFormat_t mode); /** * @brief Configure the Clock Generator Reference Clock In/Out