ThunderScope/Software/libthunderscope/thunderscopehw/thunderscopehw_internals.c

233 lines
6.4 KiB
C

#include "thunderscopehw_private.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
#else
#include <unistd.h>
#endif
enum ThunderScopeHWStatus thunderscopehw_initboard(struct ThunderScopeHW* ts)
{
THUNDERSCOPEHW_RUN(write32(ts, DATAMOVER_REG_OUT, 0));
ts->board_en = true;
THUNDERSCOPEHW_RUN(set_datamover_reg(ts));
THUNDERSCOPEHW_RUN(configure_pll(ts));
return thunderscopehw_configure_adc(ts);
}
enum ThunderScopeHWStatus thunderscopehw_fifo_write(struct ThunderScopeHW* ts, uint8_t* data, size_t bytes)
{
// reset ISR
THUNDERSCOPEHW_RUN(write32(ts, SERIAL_FIFO_ISR_ADDRESS, 0xFFFFFFFFU));
// read ISR and IER
thunderscopehw_read32(ts, SERIAL_FIFO_ISR_ADDRESS);
thunderscopehw_read32(ts, SERIAL_FIFO_IER_ADDRESS);
// enable IER
THUNDERSCOPEHW_RUN(write32(ts, SERIAL_FIFO_IER_ADDRESS, 0x0C000000U));
// Set false TDR
THUNDERSCOPEHW_RUN(write32(ts, SERIAL_FIFO_TDR_ADDRESS, 0x2U));
// Put data into queue
for(size_t i = 0; i < bytes; i++) {
// TODO: Replace with write32
THUNDERSCOPEHW_RUN(write_handle(ts, ts->user_handle, data + i, SERIAL_FIFO_DATA_WRITE_REG, 1));
}
// read TDFV (vacancy byte)
thunderscopehw_read32(ts, SERIAL_FIFO_TDFV_ADDRESS);
// write to TLR (the size of the packet)
THUNDERSCOPEHW_RUN(write32(ts, SERIAL_FIFO_TLR_ADDRESS, (uint32_t)(bytes * 4)));
// read ISR for a done value
while ((thunderscopehw_read32(ts, SERIAL_FIFO_ISR_ADDRESS) >> 24) != 8) {
#ifdef WIN32
Sleep(1);
#else
usleep(1500);
#endif
}
// reset ISR
THUNDERSCOPEHW_RUN(write32(ts, SERIAL_FIFO_ISR_ADDRESS, 0xFFFFFFFFU));
// read TDFV
thunderscopehw_read32(ts, SERIAL_FIFO_TDFV_ADDRESS);
return THUNDERSCOPEHW_STATUS_OK;
}
enum ThunderScopeHWStatus thunderscopehw_set_datamover_reg(struct ThunderScopeHW* ts)
{
uint32_t datamover_reg = 0;
int num_channels_on = 0;
if (ts->board_en) datamover_reg |= 0x01000000;
if (ts->pll_en) datamover_reg |= 0x02000000;
if (ts->fe_en) datamover_reg |= 0x04000000;
if (ts->datamover_en) datamover_reg |= 0x1;
if (ts->fpga_adc_en) datamover_reg |= 0x2;
for (int channel = 0; channel < 4; channel++) {
if (ts->channels[channel].on == true) {
num_channels_on++;
}
if (ts->channels[channel].vdiv <= 100) {
datamover_reg |= 1 << (16 + channel);
}
if (ts->channels[channel].coupling == THUNDERSCOPEHW_COUPLING_DC) {
datamover_reg |= 1 << (20 + channel);
}
}
switch (num_channels_on) {
case 0:
case 1: break; // do nothing
case 2: datamover_reg |= 0x10; break;
default: datamover_reg |= 0x30; break;
}
// write to datamover reg
return thunderscopehw_write32(ts, DATAMOVER_REG_OUT, datamover_reg);
}
// PGA LMH6518
enum ThunderScopeHWStatus thunderscopehw_set_pga(struct ThunderScopeHW* ts, int channel)
{
uint8_t fifo[4];
fifo[0] = 0xFB - channel; // SPI chip enable
fifo[1] = 0;
fifo[2] = 0x04; // ??
int vdiv = ts->channels[channel].vdiv;
if (vdiv > 100) {
// Attenuator relay on, handled by
// thunderscopehw_set_datamover_reg.
vdiv /= 100;
}
switch (vdiv) {
case 100: fifo[3] = 0x0A; break;
case 50: fifo[3] = 0x07; break;
case 20: fifo[3] = 0x03; break;
case 10: fifo[3] = 0x1A; break;
case 5: fifo[3] = 0x17; break;
case 2: fifo[3] = 0x13; break;
case 1: fifo[3] = 0x10; break;
default: return THUNDERSCOPEHW_STATUS_INVALID_VDIV;
}
switch (ts->channels[channel].bw) {
case 20: fifo[3] |= 0x40; break;
case 100: fifo[3] |= 0x80; break;
case 200: fifo[3] |= 0xC0; break;
case 350: /* 0 */ break;
default: return THUNDERSCOPEHW_STATUS_INVALID_BANDWIDTH;
}
return thunderscopehw_fifo_write(ts, fifo, 4);
}
enum ThunderScopeHWStatus thunderscopehw_set_dac(struct ThunderScopeHW* ts, int channel)
{
// value is 12-bit
// Is this right?? Or is it rounding wrong?
int dac_value = (unsigned int)round((ts->channels[channel].voffset + 0.5) * 4095);
if (dac_value < 0)
return THUNDERSCOPEHW_STATUS_OFFSET_TOO_LOW;
if (dac_value > 0xFFF)
return THUNDERSCOPEHW_STATUS_OFFSET_TOO_HIGH;
uint8_t fifo[5];
fifo[0] = 0xFF; // I2C
fifo[1] = 0xC2; // DAC?
fifo[2] = 0x40 + (channel << 1);
fifo[3] = ((dac_value >> 8) & 0xF);
fifo[4] = dac_value & 0xFF;
return thunderscopehw_fifo_write(ts, fifo, 5);
}
enum ThunderScopeHWStatus thunderscopehw_configure_channels(struct ThunderScopeHW* ts)
{
uint8_t on_channels[4];
int i;
int num_channels_on = 0;
uint8_t clkdiv = 0;
for (i = 0; i < 4; i++) {
if (ts->channels[i].on) {
on_channels[num_channels_on++] = i;
}
}
switch (num_channels_on) {
case 0:
case 1:
on_channels[1] = on_channels[2] = on_channels[3] = on_channels[0];
clkdiv = 0;
break;
case 2:
on_channels[2] = on_channels[3] = on_channels[1];
on_channels[1] = on_channels[0];
clkdiv = 1;
break;
default:
on_channels[0] = 0;
on_channels[1] = 1;
on_channels[2] = 2;
on_channels[3] = 3;
num_channels_on = 4;
clkdiv = 2;
break;
}
THUNDERSCOPEHW_RUN(adc_power(ts, false));
THUNDERSCOPEHW_RUN(adc_set_reg(ts,
THUNDERSCOPEHW_ADC_REG_CHNUM_CLKDIV,
(clkdiv << 8) | num_channels_on));
THUNDERSCOPEHW_RUN(adc_power(ts, true));
THUNDERSCOPEHW_RUN(adc_set_reg(ts,
THUNDERSCOPEHW_ADC_REG_INSEL12,
(2 << on_channels[0]) | (512 << on_channels[1])));
THUNDERSCOPEHW_RUN(adc_set_reg(ts,
THUNDERSCOPEHW_ADC_REG_INSEL34,
(2 << on_channels[2]) | (512 << on_channels[3])));
struct ThunderScopeHW tmp = *ts;
tmp.datamover_en = false;
tmp.fpga_adc_en = false;
THUNDERSCOPEHW_RUN(set_datamover_reg(&tmp));
#ifdef WIN32
Sleep(5);
#else
usleep(5000);
#endif
/* No channels, leave data mover off. */
if (num_channels_on == 0) return THUNDERSCOPEHW_STATUS_OK;
return thunderscopehw_set_datamover_reg(ts);
}
enum ThunderScopeHWStatus thunderscopehw_configure_channel(struct ThunderScopeHW* ts, int channel)
{
THUNDERSCOPEHW_RUN(configure_channels(ts));
THUNDERSCOPEHW_RUN(set_dac(ts, channel));
THUNDERSCOPEHW_RUN(set_datamover_reg(ts));
return thunderscopehw_set_pga(ts, channel);
}
uint32_t thunderscopehw_read32(struct ThunderScopeHW* ts, size_t addr)
{
uint8_t bytes[4];
if (thunderscopehw_read_handle(ts, ts->user_handle, bytes, addr, 4) != THUNDERSCOPEHW_STATUS_OK) {
fprintf(stderr, "Error in thunderscopehw_read32\n");
exit(1);
}
return (bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8) | bytes[0];
}
enum ThunderScopeHWStatus thunderscopehw_write32(struct ThunderScopeHW* ts, size_t addr, uint32_t value)
{
uint8_t bytes[4];
bytes[3] = value >> 24;
bytes[2] = value >> 16;
bytes[1] = value >> 8;
bytes[0] = value;
return thunderscopehw_write_handle(ts, ts->user_handle, bytes, addr, 4);
}