Compare commits

...

4 Commits

Author SHA1 Message Date
cnlohr 933a3d4347 Dual mode working 2024-10-09 01:05:35 -07:00
cnlohr 4c84e5e538 Working - full vector scope, no dual mode yet 2024-10-08 22:19:46 -07:00
cnlohr 01216baaf9 Update oscope code + autoreconnect in webpageo 2024-10-08 21:25:10 -07:00
cnlohr 9044689537 Middle before totally swapping to new mode 2024-10-08 19:50:22 -07:00
6 changed files with 304 additions and 177 deletions
+247 -155
View File
@@ -41,36 +41,66 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
**/
// NOT LORA!!! -- but experimenting with the possibility of rx.
// SETUP INSTRUCTIONS:
// (1) `make` in the optionbytes folder to configure `RESET` correctly.
// (2) Create a tone (if using the funprog, ../ch32v003fun/minichlink/minichlink -X ECLK 1:235:189:9:3 for 27.48387097MHz
// (2) or, for 24.387096762MHz - ../ch32v003fun/minichlink/minichlink -X ECLK 1:150:49:8:3
/* More notes
* Minimum sample time with DMA = fCPU / 28 (5.14MHz)
*/
// TODO:
// 1: Cleanup some code.
// 2: Leverage other ADC.
// 3:
#include "ch32v003fun.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// Channel for ADC
#define CHANNEL 0
// For I2C, output will be on PB8/PB9 SCL/SDA
//#define ENABLE_OLED
//#define PWM_OUTPUT
int g_volume_pwm = 127; // 0 - 127 (100%) (but you can go over 100) (For when using PWM)
#define ENABLE_OLED_SCOPE
//#define PROFILING_PIN PC8
#define SAMPLETIME 1 // 0: 1.5 cycles; 1: 7.5 cycles; 2: 13.5 cycles; (0 would go fastest and is important in single-ADC mode, but 1 seems slightly better in 2-ADC mode)
#ifdef ENABLE_OLED_SCOPE
#define SH1107_128x128
#define SSD1306_RST_PIN PA3
#define SSD1306_CS_PIN PA4
#define SSD1306_DC_PIN PA6
#define SSD1306_MOSI_PIN PA7
#define SSD1306_SCK_PIN PA5
#define SSD1306_BAUD_RATE_PRESCALER SPI_BaudRatePrescaler_4
#include "ssd1306_spi.h"
#include "ssd1306.h"
#endif
#ifdef ENABLE_OLED
#define SH1107_128x128
#define SSD1306_REMAP_I2C
//#define PWM_OUTPUT
#define ENABLE_OLED
#define PROFILING_PIN PA0
//#define SSD1306_I2C_IRQ
#include "ssd1306_i2c.h"
#include "ssd1306.h"
#endif
#if defined( ENABLE_OLED ) && defined( ENABLE_OLED_SCOPE )
#error Cant be SPI and I2C OLED
#endif
#include "./usb_config.h"
#include "../ch32v003fun/examples_v20x/otg_device/otgusb.h"
@@ -79,78 +109,22 @@ SOFTWARE.
volatile uint16_t adc_buffer[ADC_BUFFSIZE];
int g_volume_pwm = 127; // 0 - 127 (100%) (but you can go over 100)
int32_t g_goertzel_phasor_r = 32768;
int32_t g_goertzel_phasor_i = 0;
int32_t g_goertzel_advance_r = 32768;
int32_t g_goertzel_advance_i = 0;
#if 0
int g_pwm_period = (30-1);
int g_goertzel_buffer = (752);
int g_exactcompute = (0);
int32_t g_goertzel_omega_per_sample = 2485087396; // 0.368351 of whole per step / 27.031915MHz
int32_t g_goertzel_coefficient = -1453756170;
int32_t g_goertzel_coefficient_s = 1580594514;
#endif
#if 1
int g_pwm_period = (30-1);
int g_goertzel_buffer = (180);
int g_exactcompute = (0);
int32_t g_goertzel_omega_per_sample = 5509657063; // 0.816667 of whole per step / 0.880000MHz
// Very basic setup, for tuning to 880AM
int g_pwm_period = (60-1);
int g_exactcompute = (1);
int g_goertzel_buffer = (1024);
int32_t g_goertzel_omega_per_sample = 873460290; // 0.183333 of whole per step / -8.720000MHz
int32_t g_goertzel_coefficient = 873460290;
int32_t g_goertzel_coefficient_s = -1961823932;
int32_t g_goertzel_coefficient_s = 1961823932;
int32_t g_goertzel_advance_r = -3425;
int32_t g_goertzel_advance_i = 32588;
#endif
#if 0
int g_pwm_period = (31-1);
int g_goertzel_buffer = (412);
int g_exactcompute = (0);
const int32_t g_goertzel_omega_per_sample = 1670254667; // 0.247573 of whole per step / 1.150016MHz
const int32_t g_goertzel_coefficient = 32748822;
const int32_t g_goertzel_coefficient_s = 2147233926;
#endif
#if 0
int g_pwm_period = (30-1);
int g_goertzel_buffer = (576);
int g_exactcompute = (0);
int32_t g_goertzel_omega_per_sample = 1264972285; // 0.187500 of whole per step / 90.300000MHz
int32_t g_goertzel_coefficient = 821806413;
int32_t g_goertzel_coefficient_s = 1984016189;
#endif
#if 0
int g_pwm_period = (30-1);
int g_goertzel_buffer = (320);
int g_exactcompute = (0);
const int32_t g_goertzel_omega_per_sample = 990894956; // 0.146875 of whole per step / 101.505000MHz
const int32_t g_goertzel_coefficient = 1296126516;
const int32_t g_goertzel_coefficient_s = 1712233066;
#endif
#if 0
int g_pwm_period = (30-1);
int g_goertzel_buffer = (384);
int g_exactcompute = (0);
const int32_t g_goertzel_omega_per_sample = 4251712402; // 0.630208 of whole per step / 27.025000MHz
const int32_t g_goertzel_coefficient = -1468003291;
const int32_t g_goertzel_coefficient_s = -1567371161;
#endif
#if 0
int g_pwm_period = (30-1);
int g_goertzel_buffer = (336);
int g_exactcompute = (0);
const int32_t g_goertzel_omega_per_sample = 1827182189; // 0.270833 of whole per step / 89.900000MHz
const int32_t g_goertzel_coefficient = -280302863;
const int32_t g_goertzel_coefficient_s = 2129111628;
#endif
int intensity_average = 1;
#define LOG_GOERTZEL_LIST 512
@@ -162,49 +136,59 @@ void SetupADC()
// XXX TODO -look into PGA
// XXX TODO - Look into tag-teaming the ADCs
// PDA is analog input chl 7
GPIOA->CFGLR &= ~(0xf<<(4*7)); // CNF = 00: Analog, MODE = 00: Input
// PDA is analog input chl CHANNEL
GPIOA->CFGLR &= ~(0xf<<(4*CHANNEL)); // CNF = 00: Analog, MODE = 00: Input
// ADC CLK is chained off of APB2.
// Reset the ADC to init all regs
RCC->APB2PRSTR |= RCC_APB2Periph_ADC1;
RCC->APB2PRSTR &= ~RCC_APB2Periph_ADC1;
RCC->APB2PRSTR |= RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2;
RCC->APB2PRSTR &= ~( RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 );
// ADCCLK = 12 MHz => RCC_ADCPRE divide by 4
RCC->CFGR0 &= ~RCC_ADCPRE; // Clear out the bis in case they were set
RCC->CFGR0 |= RCC_ADCPRE_DIV2; // Fastest possible (divide-by-2) NOTE: This is OUTSIDE the specified value in the datasheet.
// Set up single conversion on chl 7
ADC1->RSQR1 = 0;
ADC1->RSQR2 = 0;
ADC1->RSQR3 = 7; // 0-9 for 8 ext inputs and two internals
ADC1->RSQR3 = CHANNEL; // 0-9 for 8 ext inputs and two internals Set to 7 for PA7
ADC2->RSQR3 = CHANNEL; // 0-9 for 8 ext inputs and two internals Set to 7 for PA7
ADC1->ISQR = CHANNEL; // Mirror in case we switch to injection mode.
ADC2->ISQR = CHANNEL;
// Not using injection group.
// Sampling time for channels. Careful: This has PID tuning implications.
// Note that with 3 and 3,the full loop (and injection) runs at 138kHz.
ADC1->SAMPTR2 = (0<<(3*7));
ADC1->SAMPTR2 = (SAMPLETIME<<(3*CHANNEL)); // (3*channel)
ADC2->SAMPTR2 = (SAMPLETIME<<(3*CHANNEL)); // (3*channel)
// Turn on ADC and set rule group to sw trig
// 0 = Use TRGO event for Timer 1 to fire ADC rule.
ADC1->CTLR2 = ADC_ADON | ADC_EXTTRIG | ADC_DMA;
ADC2->CTLR2 = ADC_ADON | ADC_EXTTRIG | ADC_EXTSEL_1;// | ADC_DMA;
// For EXTTRIG, EXTSEL (none) = 0 = TIM1CC1 /
// For JEXTTRIG, EXTSEL = 0 = TIM1 TRGO (Or ADC_JEXTSEL_0 => CH4)
// Reset calibration
ADC1->CTLR2 |= ADC_RSTCAL;
ADC2->CTLR2 |= ADC_RSTCAL;
while(ADC1->CTLR2 & ADC_RSTCAL);
while(ADC2->CTLR2 & ADC_RSTCAL);
// Calibrate ADC
ADC1->CTLR2 |= ADC_CAL;
ADC2->CTLR2 |= ADC_CAL;
while(ADC1->CTLR2 & ADC_CAL);
while(ADC2->CTLR2 & ADC_CAL);
// ADC_SCAN: Allow scanning.
ADC2->CTLR1 = ADC_SCAN;
ADC1->CTLR1 =
//ADC_SCAN;
ADC_SCAN | ADC_BUFEN ;
//ADC_Pga_16 | ADC_SCAN | ADC_BUFEN ;
//ADC_Pga_64 | ADC_SCAN;
//ADC_DUALMOD_0 | ADC_DUALMOD_3 | // Alternate Trigger Mode (Can't use with DMA)
ADC_SCAN;
//ADC_Pga_16 | ADC_BUFEN ;
//ADC_Pga_64 | ADC_BUFEN;
// Turn on DMA
RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
@@ -212,32 +196,21 @@ void SetupADC()
//DMA1_Channel1 is for ADC
DMA1_Channel1->PADDR = (uint32_t)&ADC1->RDATAR;
DMA1_Channel1->MADDR = (uint32_t)adc_buffer;
DMA1_Channel1->CNTR = ADC_BUFFSIZE;
DMA1_Channel1->CNTR = ADC_BUFFSIZE/2;
DMA1_Channel1->CFGR =
DMA_M2M_Disable |
DMA_Priority_VeryHigh |
DMA_MemoryDataSize_HalfWord |
DMA_PeripheralDataSize_HalfWord |
DMA_MemoryDataSize_Word |
DMA_PeripheralDataSize_Word |
DMA_MemoryInc_Enable |
DMA_Mode_Circular |
DMA_DIR_PeripheralSRC;
// NVIC_SetPriority( DMA1_Channel1_IRQn, 0<<4 ); //We don't need to tweak priority.
NVIC_EnableIRQ( DMA1_Channel1_IRQn );
DMA1_Channel1->CFGR |= DMA_CFGR1_EN | DMA_IT_TC | DMA_IT_HT; // Transmission Complete + Half Empty Interrupts.
// Turn on DMA channel 1
DMA1_Channel1->CFGR |= DMA_CFGR1_EN;
// Enable continuous conversion and DMA
ADC1->CTLR2 |= ADC_DMA; // | ADC_CONT;
// start conversion
ADC1->CTLR2 |= ADC_SWSTART;// | ADC_CONT;
}
static void SetupTimer1()
@@ -261,18 +234,80 @@ static void SetupTimer1()
TIM1->BDTR |= 0xc000;//TIM_MOE;
#endif
TIM1->CCER |= TIM_CC1E;
TIM1->CCER |= TIM_CC1E | TIM_CC4E | TIM_CC3E;
TIM1->CHCTLR1 |= TIM_OC1M_2 | TIM_OC1M_1;
TIM1->CH1CVR = 1;
TIM1->CHCTLR2 |= TIM_OC3M_2 | TIM_OC3M_1 | TIM_OC4M_2 | TIM_OC4M_1;
TIM1->CH1CVR = 1; // In case we are using rule triggering
TIM1->CH3CVR = 1; // In case we are using rule (alternate) triggering
TIM1->CH4CVR = 1; // In case we are using injection triggering
// Setup TRGO to trigger for ADC (NOTE: Not on the 203! TIM1_TRGO is only connected to injection)
//TIM1->CTLR2 = TIM_MMS_1;
// Setup TRGO to trigger for ADC injection group
TIM1->CTLR2 = TIM_MMS_1;
// Enable TIM1 outputs
TIM1->BDTR = TIM_MOE;
TIM1->CTLR1 = TIM_CEN;
}
#ifdef ENABLE_OLED_SCOPE
// Command-mode, Set X, Disable Timer, Set Y, Enable Timer
// Done this way to prevent streaking.
uint8_t cmdxy[] = { 0x00, 0xd3, 0x30, 0xd5, 0xff, 0x00, 0xdc, 0x30, 0xd5, 0xf0 };
void config_turbo_scope()
{
DMA1_Channel3->PADDR = (uint32_t)&SPI1->DATAR;
DMA1_Channel3->MADDR = (uint32_t)cmdxy;
DMA1_Channel3->CNTR = sizeof(cmdxy);
DMA1_Channel3->CFGR =
DMA_M2M_Disable |
DMA_Priority_Low |
DMA_MemoryDataSize_Byte |
DMA_PeripheralDataSize_Byte |
DMA_MemoryInc_Enable |
DMA_Mode_Normal |
DMA_DIR_PeripheralDST;
// Turn on DMA channel 3
DMA1_Channel3->CFGR |= DMA_CFGR1_EN;
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
SPI1->CTLR2 |= SPI_CTLR2_TXDMAEN;
}
void ssd1306_send_turbo(uint8_t *data, uint8_t sz)
{
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
funDigitalWrite( SSD1306_CS_PIN, FUN_LOW );
// send data
while(sz--)
{
// wait for TXE
while(!(SPI1->STATR & SPI_STATR_TXE));
// Send byte
SPI1->DATAR = *data++;
}
// wait for not busy before exiting
while(SPI1->STATR & SPI_STATR_BSY);
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
}
static void PlotPoint( int x, int y )
{
funDigitalWrite( SSD1306_CS_PIN, FUN_HIGH );
cmdxy[2] = x; cmdxy[7] = y;
DMA1_Channel3->CNTR = sizeof(cmdxy);
funDigitalWrite( SSD1306_CS_PIN, FUN_LOW );
DMA1_Channel3->CFGR |= DMA_CFGR1_EN;
}
#endif
void InnerLoop() __attribute__((noreturn));
@@ -319,7 +354,9 @@ void DMA1_Channel1_IRQHandler( void )
// Clear all possible flags.
DMA1->INTFCR = DMA1_IT_GL1;
int tpl = ADC_BUFFSIZE - DMA1_Channel1->CNTR; // Warning, sometimes this is == to the base, or == 0 (i.e. might be 256, if top is 255)
int tpl = ADC_BUFFSIZE - DMA1_Channel1->CNTR*2;
// Warning, sometimes this is DMA1_Channel1->CNTR == to the base, or == 0 (i.e. might be 256, if top is 255)
tpl += ADC_BUFFSIZE;
tpl = (tpl & (ADC_BUFFSIZE-1));
if( tpl == ADC_BUFFSIZE ) tpl = 0;
@@ -338,6 +375,9 @@ void DMA1_Channel1_IRQHandler( void )
// Here is where the magic happens.
#if 1
// Also, this is the current limiting factor for the maximum samplerate.
// We can't go above 7.2MSPS and keep up here when main CPU is @ 144MHz.
#define XSTR(x) #x
#define GOERTZELLOOP(idx) \
asm volatile("\n\
@@ -421,8 +461,9 @@ void DMA1_Channel1_IRQHandler( void )
}
// Now, rotate rr, ri by that phasor.
temp = (g_goertzel_phasor_r * ri + g_goertzel_phasor_i * rr) >> 15;
rr = (g_goertzel_phasor_r * rr - g_goertzel_phasor_i * ri) >> 15;
// To get it in line >> 15, but we also want to divide by 8 (>>3) because that makes the rest of the math easier.
temp = (g_goertzel_phasor_r * ri + g_goertzel_phasor_i * rr) >> (15+3);
rr = (g_goertzel_phasor_r * rr - g_goertzel_phasor_i * ri) >> (15+3);
ri = temp;
// rr, ri are now in the correct frame of reference. Continue computing.
@@ -430,9 +471,6 @@ void DMA1_Channel1_IRQHandler( void )
qibaselogs[qibaselogs_head] = ((uint16_t)rr) | (((uint16_t)ri)<<16);
qibaselogs_head = ( qibaselogs_head + 1 ) & ((LOG_GOERTZEL_LIST)-1);
rr>>=2;
ri>>=2;
int s = rr * rr + ri * ri;
//int intensity = 1<<( ( 32 - __builtin_clz(s) )/2);
#define ABS(x) (((x)<0)?-(x):(x))
@@ -442,6 +480,10 @@ void DMA1_Channel1_IRQHandler( void )
intensity++;
intensity = (intensity + s/intensity)/2;
intensity = (intensity + s/intensity)/2;
// intensity = rr * rr + ri * ri
// This performs a low-pass IIR without exploding intensity_average.
intensity_average = intensity_average - (intensity_average>>12) + (intensity>>6);
#ifdef PWM_OUTPUT
@@ -460,6 +502,18 @@ void DMA1_Channel1_IRQHandler( void )
adc_offset -= accumulate_over_window / g_goertzel_buffer;
accumulate_over_window = 0;
#ifdef ENABLE_OLED_SCOPE
int rrplot = rr * 1536 / (intensity_average);
int riplot = ri * 1536 / (intensity_average);
rrplot += 64;
riplot += 64;
if( rrplot < 1 ) rrplot = 1;
if( riplot < 1 ) riplot = 1;
if( rrplot > 126 ) rrplot = 126;
if( riplot > 126 ) riplot = 126;
PlotPoint( rrplot, riplot );
#endif
#ifdef PROFILING_PIN
funDigitalWrite( PROFILING_PIN, 1 );
#endif
@@ -492,7 +546,6 @@ static inline uint32_t gets2()
return ret;
}
void InnerLoop()
{
while(1){
@@ -507,13 +560,12 @@ void InnerLoop()
}
#endif
int pxa = 0;
// Only display half of the list so the other half could
// be updated by the ISR.
int glread = qibaselogs_head;
int intensity = 0;
#ifdef ENABLE_OLED
int pxa = 0;
int glread = qibaselogs_head;
for( pxa = 0; pxa < LOG_GOERTZEL_LIST; pxa++ )
{
@@ -534,12 +586,8 @@ void InnerLoop()
if( rr > 127 ) rr = 127;
if( ri > 127 ) ri = 127;
#ifdef ENABLE_OLED
ssd1306_drawPixel( rr, ri, 1 );
#endif
}
#ifdef ENABLE_OLED
//char cts[32];
//snprintf( cts, 32, "%d", intensity_average );
//ssd1306_drawstr( 0, 0, cts, 1 );
@@ -550,20 +598,43 @@ void InnerLoop()
//if( ik == sizeof(ssd1306_buffer) ) ik = 0;
ssd1306_setbuf(0);
#else
Delay_Ms(17);
#endif
// printf( "%6d %8d %8d - %8d %8d - %8d\n", g_goertzel_outs,g_goertzelp2_store, g_goertzelp_store, rr, ri, x );
// Delay_Ms(940);
//printf( "!!!!\n ");
// Do nothing.
Delay_Ms(17);
}
}
uint8_t i2c_send_buffer[16];
void setup_i2c_dma(void)
{
// Turn on DMA
RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
//DMA1_Channel6 is for I2C1TX
DMA1_Channel6->PADDR = (uint32_t)&I2C1->DATAR;
DMA1_Channel6->MADDR = (uint32_t)&i2c_send_buffer;
DMA1_Channel6->CNTR = 0;
DMA1_Channel6->CFGR =
DMA_M2M_Disable |
DMA_Priority_Low |
DMA_MemoryDataSize_Byte |
DMA_PeripheralDataSize_Byte |
DMA_MemoryInc_Enable |
DMA_Mode_Normal |
DMA_DIR_PeripheralDST |
0;
I2C1->CTLR2 = I2C_CTLR2_DMAEN | 0b111100;
DMA1_Channel6->CFGR |= DMA_CFGR1_EN;
NVIC_DisableIRQ(I2C1_EV_IRQn);
printf( "INTO\n" );
}
int main()
{
SystemInit();
@@ -604,7 +675,7 @@ int main()
SetupADC();
#ifdef ENABLE_OLED
#if defined( ENABLE_OLED )
ssd1306_i2c_setup();
ssd1306_i2c_init();
@@ -617,32 +688,49 @@ int main()
ssd1306_refresh();
#endif
#if 0
int i = 0;
int k = 0;
int frame = 0;
while( 1)
{
// ssd1306_drawLine( (frame)%128, (0)%128, (0)%128, (127-frame)%128, 1 );
ssd1306_drawstr( frame%128, frame%128, "hello", 1 );
#ifdef ENABLE_OLED_SCOPE
int i;
ssd1306_refresh();
ssd1306_setbuf(0);
frame++;
ssd1306_spi_init();
ssd1306_rst();
if( ssd1306_init() )
printf( "Failed to initialize OLED\n" );
else
printf( "Initialized OLED\n" );
ssd1306_setbuf(0);
// Setup a diagonal to allow for vector mode.
for( i = 0; i < 128; i++ )
{
ssd1306_drawPixel( i, i, 1 );
//ssd1306_drawPixel( i+1, i, 1 );
}
while(1);
ssd1306_refresh();
uint8_t force_two_row_mode[] = {
0xa8, 0, // Set MUX ratio (Actually # of lines to scan) (But it's this + 1) You can make this 1 for wider.
};
ssd1306_pkt_send(force_two_row_mode, sizeof( force_two_row_mode ) , 1);
uint8_t force_max_speed[] = {
0xd5, 0xf0
};
ssd1306_pkt_send(force_max_speed, sizeof( force_max_speed ) , 1);
config_turbo_scope();
#if 0 // Test streaking
int rframe = 0;
while(1)
{
PlotPoint( rframe & 0xff, rframe>>8 );
rframe++;
//Delay_Ms(1);
}
#endif
#if 0
// turn on the op-amp
EXTEN->EXTEN_CTR |= EXTEN_OPA_EN;
// select op-amp pos pin: 0 = PA2, 1 = PD7
EXTEN->EXTEN_CTR |= EXTEN_OPA_PSEL;
// select op-amp neg pin: 0 = PA1, 1 = PD0
EXTEN->EXTEN_CTR |= EXTEN_OPA_NSEL;
#endif
#ifdef PROFILING_PIN
@@ -743,7 +831,7 @@ void HandleHidUserReportOutComplete( struct _USBState * ctx )
uint32_t * configs = (uint32_t*)scratchpad;
// Note: configs[0] == 0xac (command type)
printf( "Is Configure Packet %08x\n", configs[1] );
//printf( "Is Configure Packet %08x\n", configs[1] );
int numconfigs = configs[1];
if( numconfigs > 0) g_pwm_period = configs[2];
@@ -762,13 +850,13 @@ void HandleHidUserReportOutComplete( struct _USBState * ctx )
// Consider using PGA.
//ADC_Pga_16 | ADC_SCAN | ADC_BUFEN ;
//ADC_Pga_64 | ADC_SCAN;
ADC1->CTLR1 =
ADC_SCAN | ADC_BUFEN;
ADC1->CTLR1 |= ADC_BUFEN;// | ADC_Pga_4; // Adding PGA causes wild oscillation.
ADC1->CTLR2 |= ADC_BUFEN;// | ADC_Pga_4;
}
else
{
ADC1->CTLR1 =
ADC_SCAN;
ADC1->CTLR1 &= (~ADC_BUFEN);
ADC2->CTLR1 &= (~ADC_BUFEN);
}
}
@@ -776,6 +864,10 @@ void HandleHidUserReportOutComplete( struct _USBState * ctx )
g_goertzel_samples = 0;
TIM1->ATRLR = g_pwm_period;
TIM1->CH1CVR = 1;
TIM1->CH3CVR = TIM1->ATRLR/2+1;
g_isConfigurePacket = 0;
}
return;
+42 -8
View File
@@ -22,6 +22,7 @@ function DrawSpan( rowspan, colspan, freq, target, docolor, extrastr = "" )
return ret;
}
var system_rate = 288000000; // in MHz for effective ADC (note: This can be 2x normal clock if in dual ADC mode)
var lastGn;
var lastGmhz;
var lastGfr;
@@ -62,7 +63,7 @@ function SendGoertz()
var g_exactcompute = exact_compute;
textarea.value =
"int g_pwm_period = ("+n+"-1);\n" +
"int g_pwm_period = ("+n+"-1); // " + system_rate/lastGn/1000000. + " MHz Samplerate\n" +
"int g_exactcompute = ("+exact_compute+");\n" +
"int g_goertzel_buffer = ("+brf+");\n" +
"int32_t g_goertzel_omega_per_sample = " + g_goertzel_coefficient.toFixed(0) + "; // " + ( omega / (3.1415926535*2.0)).toFixed(6) + " of whole per step / " + mhz.toFixed(6) + "MHz\n" +
@@ -95,7 +96,8 @@ function SendGoertz()
for( var i = 0|0; i < 10; i++ )
{
var tc = (tz / 1000000000.0) % 10;
document.getElementById( "mhzm" + i ).value = tc|0;
if( document.getElementById( "mhzm" + i ) )
document.getElementById( "mhzm" + i ).value = tc|0;
tz *= 10;
}
}
@@ -131,6 +133,8 @@ function mhzm( event, ths )
let goertzel2 = document.getElementById("GOERTZEL2").checked;
let quanta = Math.round(Number(document.getElementById("quanta").value));
let quantasearch = Math.round(Number(document.getElementById("quantasearch").value));
SaveDefaults();
system_rate = xtal *1000000;
let n = lastGn;
let freq = ( xtal / n );
@@ -167,7 +171,7 @@ function computeTable()
let goertzel2 = document.getElementById("GOERTZEL2").checked;
let quanta = Math.round(Number(document.getElementById("quanta").value));
let quantasearch = Math.round(Number(document.getElementById("quantasearch").value));
SaveDefaults();
const max_harmonics = 28|0;
const min_harmonics = (quadrature?1:0)|0;
@@ -206,6 +210,7 @@ function computeTable()
if( goertzels || quadrature )
{
contents += "<input type=checkbox ID=toggle_adc_buffer onchange='toggleBuffer(this)'><label for=toggle_buffer>ADC Buffer Enable</label><BR>Scroll Wheel Control:<BR>";
contents += "<TABLE BORDER=1>";
contents += '<TR><TH>d\\h</div></TH>';
for( let h = 0|min_harmonics; h <= max_harmonics; h++ )
@@ -279,7 +284,7 @@ function computeTable()
if( mode == 0 )
{
contents += "<TD COLSPAN=2>"
if( tgoertzelp == h ) contents += "<SPAN ONCLICK='Goertz(" + n + ", " + freq * (h+goertzelpoint) + ", " + (goertzelpoint) + ", " + quantaA + ", 0)'>↑" + (goertzelpoint).toFixed(6) + "</SPAN>";
if( tgoertzelp == h ) contents += "<INPUT TYPE=SUBMIT ONCLICK='Goertz(" + n + ", " + freq * (h+goertzelpoint) + ", " + (goertzelpoint) + ", " + quantaA + ", 0)' VALUE='↑" + (goertzelpoint).toFixed(6) + "'/>";
contents += "</TD>";
}
else if( mode == 1 )
@@ -289,7 +294,7 @@ function computeTable()
else if( mode == 2 )
{
contents += "<TD COLSPAN=2>"
if( tgoertzelpi == h-1 ) contents += "<SPAN ONCLICK='Goertz(" + n + ", " + freq * (h-goertzelpointinv) + ", " + goertzelpointinv + ", " + quantaINV + ", 0)'>↓" + goertzelpointinv.toFixed(6) + "</SPAN>";
if( tgoertzelpi == h-1 ) contents += "<INPUT TYPE=SUBMIT ONCLICK='Goertz(" + n + ", " + freq * (h-goertzelpointinv) + ", " + goertzelpointinv + ", " + quantaINV + ", 0)' VALUE='↓" + goertzelpointinv.toFixed(6) + "'/>";
contents += "</TD>";
}
else if( mode == 3 )
@@ -328,7 +333,7 @@ function computeTable()
contents += "<TH COLSPAN=1>" + h + "</TH>";
}
for( let n = 0|28; n <= 96; n++ )
for( let n = 0|28; n <= 96; n+=2 )
{
let freq = ( xtal / n );
let goertzelpoint = 0;
@@ -358,7 +363,7 @@ function computeTable()
if( rid == 0 )
{
contents += "<TD COLSPAN=1 ROWSPAN=2>"
contents += "<SPAN ONCLICK='Goertz(" + n + ", " + freq * (h+tgoertzelpoint) + ", " + (tgoertzelpoint) + ", " + quantaA + ", 1)'>↑" + n + "</SPAN>";
contents += "<INPUT TYPE=SUBMIT ONCLICK='Goertz(" + n + ", " + freq * (h+tgoertzelpoint) + ", " + (tgoertzelpoint) + ", " + quantaA + ", 1)' VALUE='↑" + n + "'/>";
contents += "</TD>"
}
}
@@ -386,8 +391,37 @@ function computeTable()
document.getElementById( "TABLE" ).innerHTML = contents;
}
const savedFields = ["crystalmhz", "targetmhz", "QUADRATURE", "GOERTZELS", "GOERTZELS2", "quanta", "quantasearch"];
function SaveDefaults()
{
for( i in savedFields )
{
let f = savedFields[i];
let e = document.getElementById(f);
if( e )
{
localStorage.setItem( f, e.value );
}
}
}
function LoadDefaults()
{
for( i in savedFields )
{
let f = savedFields[i];
let e = document.getElementById(f);
if( e && localStorage.getItem( f ) )
{
e.value = localStorage.getItem( f );
}
}
}
function onLoad()
{
LoadDefaults();
onLoadWebHidControl();
}
</SCRIPT>
@@ -406,7 +440,7 @@ function onLoad()
<TR>
<TD VALIGN=TOP>
<TABLE WIDTH=480>
<TR><TD>Crystal MHz</TD><TD><INPUT ID=crystalmhz VALUE=144></TD></TR>
<TR><TD>System Rate MHz</TD><TD><INPUT ID=crystalmhz VALUE=288></TD></TR>
<TR><TD>Target MHz</TD><TD><INPUT ID=targetmhz VALUE=27.019360></TD></TR>
<TR><TD>Quanta</TD><TD><INPUT ID=quanta VALUE=1024> (Goertzel's Only)</TD></TR>
<TR><TD>Quanta Search Range</TD><TD><INPUT ID=quantasearch VALUE=64> (Goertzel's Only)</TD></TR>
+10 -7
View File
@@ -57,6 +57,7 @@ async function closeDeviceTool()
{
loopAbort = false;
setStatusError( "Disconnected" );
dev = null;
}
var playingAudioProcessor = null;
@@ -109,7 +110,7 @@ async function toggleAudio()
if( n == this.rbuffertail ) \
{ \
this.rbuffertail = (this.rbuffertail + (1|0))%(8192|0); \
console.log( `Overflow` ); \
/*console.log( `Overflow` ); */ \
} \
var vv = e.data[i]; \
this.dcoffset = this.dcoffset * 0.995 + vv * 0.005; \
@@ -127,7 +128,7 @@ async function toggleAudio()
var s = Math.fround( this.sampleplace ); /*float*/ \
var tail = this.rbuffertail | 0; /* int*/ \
var tailnext = this.rbuffertail | 0; /* int*/ \
if( tail == this.rbufferhead ) { console.log( "Underflow " ); return true; }\
if( tail == this.rbufferhead ) { /*console.log( "Underflow " );*/ return true; }\
var tsamp = Math.fround( this.rbuffer[tail] ); \
var nsamp = Math.fround( this.rbuffer[tailnext] ); \
this.totalsampcount += len|0; \
@@ -139,7 +140,7 @@ async function toggleAudio()
s -= excess; \
tail = ( tail + (excess|0) ) % (8192|0); \
tailnext = ( tail + (1|0) ) % (8192|0); \
if( tail == this.rbufferhead ) { console.log( "Underflow" ); break; } \
if( tail == this.rbufferhead ) { /* console.log( "Underflow" ); */ break; } \
tsamp = Math.fround( this.rbuffer[tail] ); \
nsamp = Math.fround( this.rbuffer[tailnext] ); \
} \
@@ -186,7 +187,7 @@ async function toggleAudio()
gainParam.setValueAtTime( 0, audioContext.currentTime );
}
var newVal = 0.1 - targetGain;
var newVal = 0.5 - targetGain;
console.log( "Setting gain to: " + newVal );
let gainParam = playingAudioProcessor.parameters.get("gain");
gainParam.setValueAtTime( newVal, audioContext.currentTime);
@@ -267,6 +268,7 @@ let receiveReport = null;
async function sendLoopError( e )
{
console.log( "SEND LOOP ERROR" );
sendReport = null;
receiveReport = null;
if( dev ) await dev.close();
@@ -308,7 +310,7 @@ async function sendLoop()
while( true )
{
if( dev && !loopAbort )
if( dev && dev !== null && !loopAbort )
{
receiveReport = dev.receiveFeatureReport( 0xAD ).catch( sendLoopError );
if( !receiveReport ) sendLoopError( "error creating receiveReport" );
@@ -354,7 +356,7 @@ async function sendLoop()
ctx.fillStyle = `rgb( 255 255 255 )`;
let mulcoeff = 10000.0 / lastIntensity;
let mulcoeff = 30000.0 / lastIntensity;
var lot = 1.2;
var x = 253;
@@ -452,7 +454,7 @@ async function sendLoop()
if( audioContext != null && playingAudioProcessor != null )
{
// TODO: Use crystalmhz
let sampleAdvance = (144000000.0/sample_divisor) / audioContext.sampleRate;
let sampleAdvance = (system_rate/sample_divisor) / audioContext.sampleRate;
let sampleAdvanceParam = playingAudioProcessor.parameters.get("sampleAdvance");
sampleAdvanceParam.setValueAtTime( sampleAdvance, audioContext.currentTime);
playingAudioProcessor.port.postMessage( demodbuffer );
@@ -494,5 +496,6 @@ async function sendLoop()
}
}
}
console.log( "ABORT\n" );
}
+4 -6
View File
@@ -223,7 +223,6 @@ blocks:
alias: ''
comment: ''
en_uvec: 'True'
log_level: info
states:
bus_sink: false
bus_source: false
@@ -467,7 +466,7 @@ blocks:
ant8: ''
ant9: ''
args: '"airspy=0"'
bb_gain0: '10'
bb_gain0: '25'
bb_gain1: '20'
bb_gain10: '20'
bb_gain11: '20'
@@ -604,7 +603,7 @@ blocks:
dc_offset_mode7: '0'
dc_offset_mode8: '0'
dc_offset_mode9: '0'
freq0: '1090000000'
freq0: '100000000'
freq1: 100e6
freq10: 100e6
freq11: 100e6
@@ -636,7 +635,7 @@ blocks:
freq7: 100e6
freq8: 100e6
freq9: 100e6
gain0: '10'
gain0: '25'
gain1: '10'
gain10: '10'
gain11: '10'
@@ -700,7 +699,7 @@ blocks:
gain_mode7: 'False'
gain_mode8: 'False'
gain_mode9: 'False'
if_gain0: '10'
if_gain0: '25'
if_gain1: '20'
if_gain10: '20'
if_gain11: '20'
@@ -1282,4 +1281,3 @@ connections:
metadata:
file_format: 1
grc_version: 3.10.7.0