PSDR/Source/src/main.c

1606 lines
46 KiB
C

//
// This file is part of the GNU ARM Eclipse distribution.
// Copyright (c) 2014 Liviu Ionescu.
//
// ----------------------------------------------------------------------------
//#define ARM_MATH_CM4
#include "main.h"
// ----------------------------------------------------------------------------
//
// Standalone STM32F4 led blink sample (trace via NONE).
//
// In debug configurations, demonstrate how to print a greeting message
// on the trace device. In release configurations the message is
// simply discarded.
//
// Then demonstrates how to blink a led with 1Hz, using a
// continuous loop and SysTick delays.
//
// Trace support is enabled by adding the TRACE macro definition.
// By default the trace messages are forwarded to the NONE output,
// but can be rerouted to any device or completely suppressed, by
// changing the definitions required in system/src/diag/trace_impl.c
// (currently OS_USE_TRACE_ITM, OS_USE_TRACE_SEMIHOSTING_DEBUG/_STDOUT).
//
// ----- Timing definitions -------------------------------------------------
// Keep the LED on for 2/3 of a second.
#define BLINK_ON_TICKS (TIMER_FREQUENCY_HZ * 2 / 3)
#define BLINK_OFF_TICKS (TIMER_FREQUENCY_HZ - BLINK_ON_TICKS)
// ----- main() ---------------------------------------------------------------
// Sample pragmas to cope with warnings. Please note the related line at
// the end of this function, used to pop the compiler diagnostics status.
#pragma GCC diagnostic push
//#pragma GCC diagnostic ignored "-Wunused-parameter"
//#pragma GCC diagnostic ignored "-Wmissing-declarations"
//#pragma GCC diagnostic ignored "-Wreturn-type"
void dac1SetValue(uint16_t value);
void dac2SetValue(uint16_t value);
//void ddsPrefix(void);
//void sendToDds(uint16_t data1, uint16_t data2);
#define FFT_SIZE 256 //supported sizes are 16, 64, 256, 1024
#define FFT_BUFFER_SIZE 512 //double the FFT_SIZE above.
__IO long long millis = 0;
float afGain = 1.0;
float afGainLast = 2.0;
float afGainStep = 0.1;
float afGainMax = 25.0;
uint16_t maxAmplitude = 0;
float fftFilterCoeficient[FFT_BUFFER_SIZE];
float filterTemp[FFT_BUFFER_SIZE];
uint16_t filterKernelLength = 100; //what's a good value? How does it relate to the FFT size?
uint16_t menuPos = 0;
uint16_t menuEncoderTicks = 0;
uint16_t menuLastPos = 1;
uint16_t menuCount = 11;
uint32_t frequencyDialMultiplier = 1;
long vfoAFrequency = 6111000;
long vfoALastFreq = 0;
int encoderPos, encoderLastPos;
int16_t filterUpperLimit = 68;
int16_t filterLastUpperLimit = 2;
int16_t filterLowerLimit = 0;
int16_t filterLastLowerLimit = 2;
uint8_t mode = 0;
uint8_t modeLast = 2;
float agcLevel = 0;
float agcScale = 160; //Higher is lower volume.. for now
int ifShift = 0;
float fftMaxMaxMax = 20;
float fftMaxMaxMin = 0.2;
int transmitting = 0;
unsigned int tone = 0;
uint8_t displayUpdating = 0;
/** System Clock Configuration
*/
void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
__PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 15;
RCC_OscInitStruct.PLL.PLLN = 210;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
}
void polarToRect(float m, float a, float32_t* x, float32_t* y)
{
*y = m * arm_sin_f32(a);
*x = m * arm_cos_f32(a);
}
void populateCoeficients(int bandwidth, int sideband, int offset)
{
//Chapter 17 of DSP Guide* //TODO: Make a bibliography!
//1. Take as input, desired filter response in array, both magnitude and phase (it's okay for phase to be zero)
// Looks like magnitude can be any non-negative value. First and last values of Phase must be zero.
//2. Convert to rectangular form. ***I really wish there was a built in function for this :<
//3. Run through an inverse FFT.
//4. Shift
//5. Truncate
//6. Window
//7. Reverse the FFT in preparation for FFT Convolution?
uint16_t filterKernelLength = 100; //what's a good value? How does it relate to the FFT size?
//1:
//sideband: 0 = LSB, 1 = USB, 2 = Both (AM)
//I think the code below is all wrong. At least for LSB, if the magnitude is zero, then phase doesn't matter, yeah?
if(sideband > 2) return; //Error
int i;
for(i = 0; i < FFT_BUFFER_SIZE; i++)
{
switch(sideband)
{
case 0:
if((i > FFT_BUFFER_SIZE - (offset + bandwidth)) && (i < FFT_BUFFER_SIZE - offset))
fftFilterCoeficient[i] = 1;
else
fftFilterCoeficient[i] = 0;
break;
case 1:
if((i > offset) && (i < offset + bandwidth))
fftFilterCoeficient[i] = 1;
else
fftFilterCoeficient[i] = 0;
break;
case 2:
if(((i > FFT_BUFFER_SIZE - (offset + bandwidth)) && (i < FFT_BUFFER_SIZE - offset))
|| ((i > offset) && (i < offset + bandwidth)))
fftFilterCoeficient[i] = 1;
else
fftFilterCoeficient[i] = 0;
break;
}
}
fftFilterCoeficient[FFT_BUFFER_SIZE / 2] = 0;
fftFilterCoeficient[FFT_BUFFER_SIZE - 1] = 0;
return; //Skipping all the later stuff doesn't seem to make a huge difference yet...
//2:
// float x, y;
// for(i = 0; i < FFT_SIZE; i++)
// {
// polarToRect(fftFilterCoeficient[i], fftFilterCoeficient[FFT_BUFFER_SIZE - 1 - i], &x, &y);
// fftFilterCoeficient[i] = x;
// fftFilterCoeficient[FFT_BUFFER_SIZE - 1 - i] = y;
// }
//3:
arm_cfft_radix4_instance_f32 fft_co;
arm_cfft_radix4_init_f32(&fft_co, FFT_SIZE, 1, 1);
arm_cfft_radix4_f32(&fft_co, fftFilterCoeficient);
//4:
int index;
for (i = 0; i < FFT_BUFFER_SIZE; i++)
{
index = i + filterKernelLength/2;
if(index > FFT_BUFFER_SIZE - 1) index = index - FFT_BUFFER_SIZE;
filterTemp[index] = fftFilterCoeficient[i];
}
for(i = 0; i < FFT_BUFFER_SIZE; i++)
{
fftFilterCoeficient[i] = filterTemp[i];
}
//5 & 6:
for(i = 0; i < FFT_BUFFER_SIZE; i++)
{
if(i <= filterKernelLength) fftFilterCoeficient[i] =
fftFilterCoeficient[i] * (0.54 - 0.46 * arm_cos_f32(2* 3.14159265*i/filterKernelLength));
if(i > filterKernelLength) fftFilterCoeficient[i] = 0;
}
// arm_cfft_radix4_instance_f32 fft_co;
arm_cfft_radix4_init_f32(&fft_co, FFT_SIZE, 0, 1);
arm_cfft_radix4_f32(&fft_co, fftFilterCoeficient);
// for(i = 0; i < FFT_SIZE; i++)
// {
// filterTemp[i] = fftFilterCoeficient[i * 2];
// filterTemp[FFT_BUFFER_SIZE - 1 - i] = fftFilterCoeficient[i * 2 + 1];
// }
//
// for(i = 0; i < FFT_BUFFER_SIZE; i++)
// {
// fftFilterCoeficient[i] = filterTemp[i];
// }
}
void applyCoeficient(float *samples, int shift)
{
//See DSP Guide Chapter 9 (Equation 9-1)
int i;
for(i = 0; i < FFT_SIZE; i++)
{
filterTemp[i * 2] = samples[i * 2] * fftFilterCoeficient[i * 2] - samples[i * 2 + 1] * fftFilterCoeficient[i * 2 + 1];
filterTemp[i * 2 + 1] = samples[i * 2 + 1] * fftFilterCoeficient[i * 2 + 1] + samples[i * 2] * fftFilterCoeficient[i * 2];
}
int shifter;
for(i = 0; i < FFT_BUFFER_SIZE; i++)
{
shifter = i + 2 * shift;
if(i < 0) samples[i] = 0;
if(i > FFT_BUFFER_SIZE - 1) samples[i] = 0;
samples[i] = filterTemp[i + 2 * shift];
}
}
void setupPeripheralPower()
{
__GPIOA_CLK_ENABLE();
__GPIOB_CLK_ENABLE();
__GPIOC_CLK_ENABLE();
__GPIOD_CLK_ENABLE();
__GPIOE_CLK_ENABLE();
__DMA1_CLK_ENABLE();
__DMA2_CLK_ENABLE();
}
void configDMA(SPI_HandleTypeDef *hspi)
{
static DMA_HandleTypeDef hdma_tx;
static DMA_HandleTypeDef hdma_rx;
hdma_tx.Instance = SPIx_TX_DMA_STREAM;
hdma_tx.Init.Channel = SPIx_TX_DMA_CHANNEL;
hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_tx.Init.Mode = DMA_NORMAL;
hdma_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_tx.Init.MemBurst = DMA_MBURST_INC4;
hdma_tx.Init.PeriphBurst = DMA_PBURST_INC4;
HAL_DMA_Init(&hdma_tx);
/* Associate the initialized DMA handle to the the SPI handle */
__HAL_LINKDMA(hspi, hdmatx, hdma_tx);
/* Configure the DMA handler for Transmission process */
hdma_rx.Instance = SPIx_RX_DMA_STREAM;
hdma_rx.Init.Channel = SPIx_RX_DMA_CHANNEL;
hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_rx.Init.Mode = DMA_NORMAL;
hdma_rx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_rx.Init.MemBurst = DMA_MBURST_INC4;
hdma_rx.Init.PeriphBurst = DMA_PBURST_INC4;
HAL_DMA_Init(&hdma_rx);
/* Associate the initialized DMA handle to the the SPI handle */
__HAL_LINKDMA(hspi, hdmarx, hdma_rx);
/*##-4- Configure the NVIC for DMA #########################################*/
/* NVIC configuration for DMA transfer complete interrupt (SPI3_TX) */
HAL_NVIC_SetPriority(15/*SPIx_DMA_TX_IRQn*/, 0, 1);
HAL_NVIC_EnableIRQ(SPIx_DMA_TX_IRQn);
/* NVIC configuration for DMA transfer complete interrupt (SPI3_RX) */
HAL_NVIC_SetPriority(SPIx_DMA_RX_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPIx_DMA_RX_IRQn);
//HAL_DMA_Start();
}
void doNothing()
{
static int cap = 0;
cap++;
}
void
SysTick_Handler (void)
{
millis++;
timer_tick ();
Tick();
if(timingDelay > 0) timingDelay--;
}
int clickMultiply;
int Max;
int Min;
int Pos;
int Position;
int Position2;
int isFwd;
#define EncoderPinA 20 // Rotary Encoder Left Pin //
#define EncoderPinB 19 // Rotary Encoder Right Pin //
#define EncoderPinP 21 // Rotary Encoder Click //
Encoder()
{
Position = 0;
Position2 = 0;
Max = 127;
Min = 0;
clickMultiply = 100;
}
void Tick(void)
{
if(!displayUpdating)
{
Position2 = (HAL_GPIO_ReadPin(encoderB.port, encoderB.pin) * 2) + HAL_GPIO_ReadPin(encoderA.port, encoderA.pin);;
if (Position2 != Position)
{
isFwd = ((Position == 0) && (Position2 == 1)) || ((Position == 1) && (Position2 == 3)) ||
((Position == 3) && (Position2 == 2)) || ((Position == 2) && (Position2 == 0));
if (!HAL_GPIO_ReadPin(encoderP.port, encoderP.pin))
{
if (isFwd) menuEncoderTicks += 1;
else menuEncoderTicks -= 1;
menuPos = menuEncoderTicks/2;
menuPos = menuPos % menuCount;
}
else
{
if (isFwd) Pos++;
else Pos--;
}
//if (Pos < Min) Pos = Min;
//if (Pos > Max) Pos = Max;
}
Position = Position2;
}
}
int getPos(void)
{
return (Pos/2);
}
// uint16_t getMenuPos(void)
// {
// return (menuPos/2);
// }
void setMinMax(int _Min, int _Max)
{
Min = _Min*4;
Max = _Max*4;
if (Pos < Min) Pos = Min;
if (Pos > Max) Pos = Max;
}
float samplesA[FFT_BUFFER_SIZE];
float samplesB[FFT_BUFFER_SIZE];
float samplesC[FFT_BUFFER_SIZE];
float samplesDisplay[FFT_BUFFER_SIZE];
float samplesDemod[FFT_BUFFER_SIZE];
float samplesOverlap[200]; //filterkernellength*2
int sampleBankAReady = 0;
int sampleBankBReady = 0;
int sampleBankCReady = 0;
uint8_t waterfallBusy = 0;
//float outputSamplesA[512];
//float outputSamplesB[512];
int sampleBank = 0;
//int sampleCounter = 0;
//const int FFT_SIZE = 256;
float observerA, observerB, observerC;
int dcOffset1 = 1029;
int dcOffset2 = 1535;
int dcOffset3 = 1518;
void captureSamples()
{
if(adcConfigured)
{
//if(!sampleRun)
{
if(sampleIndex == 100)
blink_led_on();
adcGetConversion();
switch (sampleBank)
{
case 0:
if(transmitting == 0)
{
samplesA[sampleIndex*2] = ((uhADCxConvertedValue3 - dcOffset3)/4096.0); // - 2048;
samplesA[sampleIndex*2 + 1] = ((uhADCxConvertedValue2 - dcOffset2)/4096.0); // - 2048;//0.0;
} else {
samplesA[sampleIndex*2] = ((uhADCxConvertedValue1 - dcOffset1)/4096.0); // - 2048;
samplesA[sampleIndex*2 + 1] = ((uhADCxConvertedValue1 - dcOffset1)/4096.0); // - 2048;//0.0;
}
if(uhADCxConvertedValue1 > maxAmplitude) maxAmplitude = uhADCxConvertedValue1;
if(uhADCxConvertedValue2 > maxAmplitude) maxAmplitude = uhADCxConvertedValue2;
if(samplesB[sampleIndex*2] > agcLevel) agcLevel = samplesB[sampleIndex*2];
if(samplesB[sampleIndex*2+1] > agcLevel) agcLevel = samplesB[sampleIndex*2+1];
// if(sampleIndex < filterKernelLength)
// {
// dac1SetValue(samplesB[sampleIndex*2] + samplesA[(FFT_SIZE - filterKernelLength)
// + sampleIndex * 2] /*/ (agcLevel * agcScale)*/ * 4096 * gain + 2048);
// dac2SetValue(samplesB[sampleIndex*2+1] + samplesA[(FFT_SIZE - filterKernelLength)
// + sampleIndex * 2] /*/ (agcLevel * agcScale)*/ * 4096 * gain + 2048);
// } else {
dac1SetValue(samplesB[(sampleIndex)*2] /*/ (agcLevel * agcScale)*/ * 4096 * afGain + 2048);
dac2SetValue(samplesB[(sampleIndex)*2+1] /*/ (agcLevel * agcScale)*/ * 4096 * afGain + 2048);
// }
if(sampleIndex >= FFT_SIZE - filterKernelLength - 1)
{
samplesOverlap[(sampleIndex - (FFT_SIZE - filterKernelLength))*2] = samplesA[sampleIndex*2];
samplesOverlap[(sampleIndex - (FFT_SIZE - filterKernelLength)) * 2 +1] = samplesA[sampleIndex*2+1];
}
break;
case 1:
if(transmitting == 0)
{
samplesB[sampleIndex*2] = ((uhADCxConvertedValue3 - dcOffset3)/4096.0); // - 2048;
samplesB[sampleIndex*2 + 1] = ((uhADCxConvertedValue2 - dcOffset2)/4096.0); // - 2048;//0.0;
} else {
samplesB[sampleIndex*2] = ((uhADCxConvertedValue1 - dcOffset1)/4096.0); // - 2048;
samplesB[sampleIndex*2 + 1] = ((uhADCxConvertedValue1 - dcOffset1)/4096.0); // - 2048;//0.0;
}
if(uhADCxConvertedValue1 > maxAmplitude) maxAmplitude = uhADCxConvertedValue1;
if(uhADCxConvertedValue2 > maxAmplitude) maxAmplitude = uhADCxConvertedValue2;
if(samplesC[sampleIndex*2] > agcLevel) agcLevel =samplesC[sampleIndex*2];
if(samplesC[sampleIndex*2+1] > agcLevel) agcLevel = samplesC[sampleIndex*2+1];
// if(sampleIndex < filterKernelLength)
// {
// dac1SetValue(samplesC[sampleIndex*2] + samplesB[(FFT_SIZE - filterKernelLength)
// + sampleIndex * 2] /*/ (agcLevel * agcScale)*/ * 4096 * gain + 2048);
// dac2SetValue(samplesC[sampleIndex*2+1] + samplesB[(FFT_SIZE - filterKernelLength)
// + sampleIndex * 2] /*/ (agcLevel * agcScale)*/ * 4096 * gain + 2048);
// } else {
dac1SetValue(samplesC[(sampleIndex)*2] /*/ (agcLevel * agcScale)*/ * 4096 * afGain + 2048);
dac2SetValue(samplesC[(sampleIndex)*2+1] /*/ (agcLevel * agcScale)*/ * 4096 * afGain + 2048);
// }
if(sampleIndex >= FFT_SIZE - filterKernelLength - 1)
{
samplesOverlap[(sampleIndex - (FFT_SIZE - filterKernelLength))*2] = samplesB[sampleIndex*2];
samplesOverlap[(sampleIndex - (FFT_SIZE - filterKernelLength)) * 2 +1] = samplesB[sampleIndex*2+1];
}
break;
case 2:
if(transmitting == 0)
{
samplesC[sampleIndex*2] = ((uhADCxConvertedValue3 - dcOffset3)/4096.0); // - 2048;
samplesC[sampleIndex*2 + 1] = ((uhADCxConvertedValue2 - dcOffset2)/4096.0); // - 2048;//0.0;
} else {
samplesC[sampleIndex*2] = ((uhADCxConvertedValue1 - dcOffset1)/4096.0); // - 2048;
samplesC[sampleIndex*2 + 1] = ((uhADCxConvertedValue1 - dcOffset1)/4096.0); // - 2048;//0.0;
}
if(uhADCxConvertedValue1 > maxAmplitude) maxAmplitude = uhADCxConvertedValue1;
if(uhADCxConvertedValue2 > maxAmplitude) maxAmplitude = uhADCxConvertedValue2;
if(samplesA[sampleIndex*2] > agcLevel) agcLevel = samplesA[sampleIndex*2];
if(samplesA[sampleIndex*2+1] > agcLevel) agcLevel = samplesA[sampleIndex*2+1];
// if(sampleIndex < filterKernelLength)
// {
// dac1SetValue(samplesA[sampleIndex*2] + samplesC[(FFT_SIZE - filterKernelLength)
// + sampleIndex * 2] /*/ (agcLevel * agcScale)*/ * 4096 * gain + 2048);
// dac2SetValue(samplesA[sampleIndex*2+1] + samplesC[(FFT_SIZE - filterKernelLength)
// + sampleIndex * 2] /*/ (agcLevel * agcScale)*/ * 4096 * gain + 2048);
// } else {
dac1SetValue(samplesA[(sampleIndex)*2] /*/ (agcLevel * agcScale)*/ * 4096 * afGain + 2048);
dac2SetValue(samplesA[(sampleIndex)*2+1] /*/ (agcLevel * agcScale)*/ * 4096 * afGain + 2048);
// }
if(sampleIndex >= FFT_SIZE - filterKernelLength - 1)
{
samplesOverlap[(sampleIndex - (FFT_SIZE - filterKernelLength))*2] = samplesC[sampleIndex*2];
samplesOverlap[(sampleIndex - (FFT_SIZE - filterKernelLength)) * 2 +1] = samplesC[sampleIndex*2+1];
}
break;
}
//dac1SetValue(outputSamplesA[sampleIndex*2]);
agcLevel = agcLevel * (1 - 0.0001);
sampleIndex++;
if(sampleIndex >= FFT_SIZE) //- (filterKernelLength/2))
{
blink_led_off();
sampleRun = 1;
sampleIndex = filterKernelLength; ///2; //0;
switch(sampleBank)
{
case 0:
sampleBankAReady = 1;
sampleBank = 1;
zeroSampleBank(samplesB);
break;
case 1:
sampleBankBReady = 1;
sampleBank = 2;
zeroSampleBank(samplesC);
break;
case 2:
sampleBankCReady = 1;
sampleBank = 0;
zeroSampleBank(samplesA);
break;
}
//sampleBank = sampleBank++ % 3;
// if(sampleBank == 0)
// {
// sampleBankAReady = 1;
// sampleBank = 1;
//
// } else {
// sampleBankBReady = 1;
// sampleBank = 0;
// }
}
adcStartConversion();
}
}
}
void zeroSampleBank(float *samples)
{
uint16_t i;
for(i = 0; i < filterKernelLength * 2; i++)
samples[i] = samplesOverlap[i];
for(; i < FFT_BUFFER_SIZE; i++)
samples[i] = 0;
}
//Seems to be working, higher numbers are higher gain. I'll need to work out the math on how much.
void setGainPot(uint8_t a, uint8_t b)
{
uint8_t i;
//pull NSS low
HAL_GPIO_WritePin(GAIN_POT_NSS.port, GAIN_POT_NSS.pin, 0);
//choose first register
HAL_GPIO_WritePin(GAIN_POT_MOSI.port, GAIN_POT_MOSI.pin, 0);
HAL_GPIO_WritePin(GAIN_POT_SCLK.port, GAIN_POT_SCLK.pin, 0);
HAL_GPIO_WritePin(GAIN_POT_SCLK.port, GAIN_POT_SCLK.pin, 1);
for(i = 0; i < 8; i++)
{
HAL_GPIO_WritePin(GAIN_POT_MOSI.port, GAIN_POT_MOSI.pin, (a >> (7-i)) & 1);
HAL_GPIO_WritePin(GAIN_POT_SCLK.port, GAIN_POT_SCLK.pin, 0);
HAL_GPIO_WritePin(GAIN_POT_SCLK.port, GAIN_POT_SCLK.pin, 1);
}
HAL_GPIO_WritePin(GAIN_POT_NSS.port, GAIN_POT_NSS.pin, 1);
HAL_GPIO_WritePin(GAIN_POT_NSS.port, GAIN_POT_NSS.pin, 0);
//choose second register
HAL_GPIO_WritePin(GAIN_POT_MOSI.port, GAIN_POT_MOSI.pin, 1);
HAL_GPIO_WritePin(GAIN_POT_SCLK.port, GAIN_POT_SCLK.pin, 0);
HAL_GPIO_WritePin(GAIN_POT_SCLK.port, GAIN_POT_SCLK.pin, 1);
for(i = 0; i < 8; i++)
{
HAL_GPIO_WritePin(GAIN_POT_MOSI.port, GAIN_POT_MOSI.pin, (b >> (7-i)) & 1);
HAL_GPIO_WritePin(GAIN_POT_SCLK.port, GAIN_POT_SCLK.pin, 0);
HAL_GPIO_WritePin(GAIN_POT_SCLK.port, GAIN_POT_SCLK.pin, 1);
}
HAL_GPIO_WritePin(GAIN_POT_NSS.port, GAIN_POT_NSS.pin, 1);
}
int
main(int argc, char* argv[])
{
HAL_Init();
SystemClock_Config();
//HAL_RCC_OscConfig()
// RCC_ClkInitStruct clockInitStructure;
// clockInitStructure.
// HAL_RCC_ClockConfig()
// SystemClock_Config();
// void (*systicker)();
// systicker = &doNothing();
//
//
// HAL_SYSTICK_Callback(systicker);
//hal_setSysTickCallback(doNothing());
// Send a greeting to the trace device (skipped on Release).
trace_puts("Hello ARM World!");
// At this stage the system clock should have already been configured
// at high speed.
trace_printf("System clock: %uHz\n", SystemCoreClock);
setupPeripheralPower();
//initDdsPins();
hal_setupPins();
spi_init();
configDMA(&SpiHandle );
timer_start();
blink_led_init();
blink_led_on();
populateCoeficients(filterUpperLimit - filterLowerLimit, mode, filterLowerLimit);
initDac1();
Encoder();
Adafruit_ILI9340_begin();
Adafruit_ILI9340_setRotation(1);
//Adafruit_GFX_fillScreen(ILI9340_BLACK);
Adafruit_GFX_fillScreen(ILI9340_BLACK);
//drawNextPixel test
// Adafruit_ILI9340_drawPixel(100,100,ILI9340_CYAN);
// Adafruit_ILI9340_drawNextPixel(ILI9340_BLUE);
// Adafruit_ILI9340_drawNextPixel(ILI9340_RED);
// Adafruit_ILI9340_drawNextPixel(ILI9340_WHITE);
// Adafruit_ILI9340_drawNextPixel(ILI9340_YELLOW);
// Adafruit_ILI9340_drawNextPixel(ILI9340_CYAN);
// Adafruit_ILI9340_drawNextPixel(ILI9340_RED);
// Adafruit_ILI9340_drawNextPixel(ILI9340_BLUE);
// Adafruit_ILI9340_drawNextPixel(ILI9340_RED);
// Adafruit_ILI9340_drawNextPixel(ILI9340_WHITE);
// Adafruit_ILI9340_drawNextPixel(ILI9340_YELLOW);
// Adafruit_ILI9340_drawNextPixel(ILI9340_CYAN);
// Adafruit_ILI9340_drawNextPixel(ILI9340_RED);
// while(1);
Adafruit_GFX_setTextSize(3);
Adafruit_GFX_setTextWrap(1);
Adafruit_GFX_setTextColor(ILI9340_WHITE, ILI9340_BLACK);
Adafruit_ILI9340_setVerticalScrollDefinition(0,120,200);
initAdc();
adcConfigured = 1;
adcStartConversion();
//TIM_setup();
//TIM_Config();
TIM_Try();
long long timeMeasurement = 0;
updateDisplay(1);
setGainPot(128, 128);
//MAIN LOOP - Lowest Priority
while(1)
{
//TODO: Should I shift away from 0Hz? to get away from 1/f noise? It didn's LOOK bad, but maybe it is negatively effecting things.
//I could do something where the dial moves around on screen, but if you get too close to the edge, the DDSs start moving the frequency
//Hmm, I think that's kind of a cool idea. It would be cool in two ways: it would allow you to shift the IF so you could get away from
//birdies, and it would mean that while tuning around locally, the waterfall would stay aligned in a useful way. Eventually, when I have
//sufficient display performance, I'd like to move (and scale, if applicable) the waterfall so it is properly aligned.
//Speaking of 1/f noise. It doesn't seem to be much of an issue on this radio, I wonder why? Did I design something right?
//Update: Not sure that the 1/f noise is as small an issue as I thought. It popped up when I was out in the field.
//Maybe the 1/f noise is masked by all the noise in my neighborhood?
//Also, early on, I thought it had an issue with microphonics, but it turned out that it was the connection to the computer.
//Also since this is a form of direct conversion receiver (two of them together) I was worried about AM broadcast interference
//but I haven't noticed any, again, maybe I did something right? Beginner's luck?
updateMenu();
updateDisplay(0);
drawWaterfall();
drawSMeter();
Adafruit_GFX_fillRect(310, 0, 3, 3, !HAL_GPIO_ReadPin(KEY1.port, KEY1.pin) ? ILI9340_RED : ILI9340_BLUE);
Adafruit_GFX_fillRect(310, 4, 3, 3, !HAL_GPIO_ReadPin(KEY2.port, KEY2.pin) ? ILI9340_RED : ILI9340_BLUE);
Adafruit_GFX_fillRect(310, 8, 3, 3, HAL_GPIO_ReadPin(TOUCH1.port, TOUCH1.pin) ? ILI9340_RED : ILI9340_BLUE);
Adafruit_GFX_fillRect(310, 12, 3, 3, HAL_GPIO_ReadPin(TOUCH2.port, TOUCH2.pin) ? ILI9340_RED : ILI9340_BLUE);
if(HAL_GPIO_ReadPin(TOUCH1.port, TOUCH1.pin))
{
transmitting = 1;
HAL_GPIO_WritePin(DAC_MUX.port, DAC_MUX.pin, 1); //0 = speaker/earphone. 1=TX Drivers
HAL_GPIO_WritePin(RX_MUX.port, RX_MUX.pin, 1); //Active Low
HAL_GPIO_WritePin(TX_MUX.port, TX_MUX.pin, 0); //Active Low
tone = 0;
} else {
transmitting = 0;
HAL_GPIO_WritePin(DAC_MUX.port, DAC_MUX.pin, 0); //0 = speaker/earphone. 1=TX Drivers
HAL_GPIO_WritePin(RX_MUX.port, RX_MUX.pin, 0); //Active Low
HAL_GPIO_WritePin(TX_MUX.port, TX_MUX.pin, 1); //Active Low
tone = 0;
}
}
}
float passBandRms = 0;
int lastSMeterBarWidth = 0;
void drawSMeter()
{
//Adafruit_GFX_fillRect(150, 160, 170, 3, ILI9340_BLACK);
int width = 10*log((passBandRms * 1000000) + 1);
if(width > lastSMeterBarWidth)
Adafruit_GFX_fillRect(150 + lastSMeterBarWidth, 156, width - lastSMeterBarWidth, 3, ILI9340_RED);
else
Adafruit_GFX_fillRect(150 + width, 156, lastSMeterBarWidth - width, 3, ILI9340_BLACK);
lastSMeterBarWidth = width;
}
void updateMenu()
{
switch(menuPos)
{
case 0: //1,000,000 place
frequencyDialMultiplier = 1000000;
updateVfo();
break;
case 1: //100,000 place
frequencyDialMultiplier = 100000;
updateVfo();
break;
case 2: //10,000 place
frequencyDialMultiplier = 10000;
updateVfo();
break;
case 3: //1,000 place
frequencyDialMultiplier = 1000;
updateVfo();
break;
case 4: //100 place
frequencyDialMultiplier = 100;
updateVfo();
break;
case 5: //10 place
frequencyDialMultiplier = 10;
updateVfo();
break;
case 6: //1 place
frequencyDialMultiplier = 1;
updateVfo();
break;
case 7: //Filter Lower Limit
encoderPos = getPos();
if(encoderPos != encoderLastPos)
{
filterLowerLimit += 1 * (encoderLastPos - encoderPos);
if(filterLowerLimit <= 0) filterLowerLimit = 0;
if(filterLowerLimit >= 200) filterLowerLimit = 100;
if(filterLowerLimit >= filterUpperLimit) filterLowerLimit = filterUpperLimit - 1;
encoderLastPos = encoderPos;
populateCoeficients(filterUpperLimit - filterLowerLimit, mode, filterLowerLimit);
}
break;
case 8: //Filter Upper
encoderPos = getPos();
if(encoderPos != encoderLastPos)
{
filterUpperLimit += 1 * (encoderLastPos - encoderPos);
if(filterUpperLimit <= 0) filterUpperLimit = 0;
if(filterUpperLimit >= 200) filterUpperLimit = 100;
if(filterUpperLimit <= filterLowerLimit) filterUpperLimit = filterLowerLimit + 1;
encoderLastPos = encoderPos;
populateCoeficients(filterUpperLimit - filterLowerLimit, mode, filterLowerLimit);
}
break;
case 9: //Mode
encoderPos = getPos();
if(encoderPos != encoderLastPos)
{
mode = (mode + (encoderLastPos - encoderPos)) % 3;
populateCoeficients(filterUpperLimit - filterLowerLimit, mode, filterLowerLimit);
encoderLastPos = encoderPos;
//TODO: CHANGE THE FILTER SO IT MAKES SENSE!
//Right now all this does is turns the AM decoder on and off, I guess.
}
break;
case 10: //Volume
encoderPos = getPos();
if(encoderPos != encoderLastPos)
{
afGain += afGainStep * (encoderLastPos - encoderPos);
if(afGain > afGainMax) afGain = afGainMax;
if(afGain <= 0) afGain = 0;
encoderLastPos = encoderPos;
}
break;
default:
break;
}
}
float calculateRmsOfSample(float* samples, int length)
{
int i;
float accumulatedSquares = 0;
for(i = 0; i < length; i++)
{
accumulatedSquares += samples[i] * samples[i];
}
accumulatedSquares = accumulatedSquares / length;
float32_t result;
arm_sqrt_f32(accumulatedSquares, &result);
return result;
}
#define freqVOffset 108 //120 - (8*3/2)
#define freqHOffset 142
//TODO: Should I make a menuItem struct? Would that be helpful? The menus are a pain right now...
uint8_t redItems[30];
void updateDisplay(uint8_t force)
{
displayUpdating = 1;
static char freqChar[14];
static char lastFreqChar[] = {'$','$','$','$','$','$','$','$','$','$','$','$','$','$',};
if(force)
{
//Adafruit_GFX_drawColorBitmap(180, 2, psdrLogo, 86,20, MASKWHITE);
Adafruit_GFX_drawColorBitmap(150, 90, bitmapMode, 40,12, MASKWHITE);
Adafruit_GFX_fillTriangle(126,119,136,124,136,114,ILI9340_WHITE);
Adafruit_GFX_drawColorBitmap(150, 136, bitmapFilter, 47,12, MASKWHITE);
drawNumber('.', freqHOffset + 16*2, freqVOffset + 0, MASKWHITE);
drawNumber('.', freqHOffset + 16*6, freqVOffset + 0, MASKWHITE);
Adafruit_GFX_drawColorBitmap(142, 162, bitmapSMeter, 155, 10, MASKWHITE);
Adafruit_GFX_drawColorBitmap(320 - 45 - 2, 240 - 46 - 2, bitmapHadLogo, 45, 46, MASKWHITE);
}
sprintf(&freqChar, "%8d", vfoAFrequency);
//So on each of these elements, we update when the value changes, when we're forced to, when the item becomes selected, or unselected.
if(freqChar[0] != lastFreqChar[0] || force || (menuPos != menuLastPos && (menuPos == 0 || menuLastPos == 0)))
{
drawNumber(freqChar[0], freqHOffset + 16*0, freqVOffset + 0, menuPos == 0 ? MASKRED : MASKWHITE);
}
if(freqChar[1] != lastFreqChar[1] || redItems[0] || force || (menuPos != menuLastPos && (menuPos == 0 || menuLastPos == 0)))
{
drawNumber(freqChar[1], freqHOffset + 16*1, freqVOffset + 0, menuPos == 0 ? MASKRED : MASKWHITE);
}
if(freqChar[2] != lastFreqChar[2] || force || (menuPos != menuLastPos && (menuPos == 1 || menuLastPos == 1)))
{
drawNumber(freqChar[2], freqHOffset + 16*3, freqVOffset + 0, menuPos == 1 ? MASKRED : MASKWHITE);
}
if(freqChar[3] != lastFreqChar[3] || force || (menuPos != menuLastPos && (menuPos == 2 || menuLastPos == 2)))
{
drawNumber(freqChar[3], freqHOffset + 16*4, freqVOffset + 0, menuPos == 2 ? MASKRED : MASKWHITE);
}
if(freqChar[4] != lastFreqChar[4] || force || (menuPos != menuLastPos && (menuPos == 3 || menuLastPos == 3)))
{
drawNumber(freqChar[4], freqHOffset + 16*5, freqVOffset + 0, menuPos == 3 ? MASKRED : MASKWHITE);
}
if(freqChar[5] != lastFreqChar[5] || force || (menuPos != menuLastPos && (menuPos == 4 || menuLastPos == 4)))
{
drawNumber(freqChar[5], freqHOffset + 16*7, freqVOffset + 0, menuPos == 4 ? MASKRED : MASKWHITE);
}
if(freqChar[6] != lastFreqChar[6] || force || (menuPos != menuLastPos && (menuPos == 5 || menuLastPos == 5)))
{
drawNumber(freqChar[6], freqHOffset + 16*8, freqVOffset + 0, menuPos == 5 ? MASKRED : MASKWHITE);
}
if(freqChar[7] != lastFreqChar[7] || force || (menuPos != menuLastPos && (menuPos == 6 || menuLastPos == 6)))
{
drawNumber(freqChar[7], freqHOffset + 16*9, freqVOffset + 0, menuPos == 6 ? MASKRED : MASKWHITE);
}
vfoALastFreq = vfoAFrequency;
strcpy(lastFreqChar, freqChar);
if(filterLowerLimit != filterLastLowerLimit || force || (menuPos != menuLastPos && (menuPos == 7 || menuLastPos == 7)))
{
sprintf(&freqChar, "%4d", filterLowerLimit * 40);
Adafruit_GFX_setTextSize(2);
Adafruit_GFX_setTextColor(menuPos == 7 ? ILI9340_RED : ILI9340_WHITE, ILI9340_BLACK);
Adafruit_GFX_setCursor(200, 135 );
int i;
for(i = 0; i < 4; i++)
{
Adafruit_GFX_write(freqChar[i]);
}
//Adafruit_GFX_setTextSize(3);
Adafruit_GFX_fillRect(121, 120, 3, 100 , ILI9340_BLACK);
Adafruit_GFX_fillRect(121, filterLowerLimit/2 + 120, 3, (filterUpperLimit - filterLowerLimit)/2, ILI9340_WHITE);
filterLastLowerLimit = filterLowerLimit;
}
if(filterUpperLimit != filterLastUpperLimit || force || (menuPos != menuLastPos && (menuPos == 8 || menuLastPos == 8)))
{
sprintf(&freqChar, "%-4d", filterUpperLimit * 40);
Adafruit_GFX_setTextSize(2);
Adafruit_GFX_setTextColor(menuPos == 8 ? ILI9340_RED : ILI9340_WHITE, ILI9340_BLACK);
Adafruit_GFX_setCursor(265, 135 );
int i;
for(i = 0; i < 4; i++)
{
Adafruit_GFX_write(freqChar[i]);
}
//Adafruit_GFX_setTextSize(3);
Adafruit_GFX_fillRect(121, 120, 3, 100 , ILI9340_BLACK);
Adafruit_GFX_fillRect(121, filterLowerLimit/2 + 120, 3, (filterUpperLimit - filterLowerLimit)/2, ILI9340_WHITE);
filterLastUpperLimit = filterUpperLimit;
}
if(mode != modeLast || force || (menuPos != menuLastPos && (menuPos == 9 || menuLastPos == 9)))
{
switch(mode)
{
case 0: //LSB
Adafruit_GFX_drawColorBitmap(196, 91, bitmapLSB, 28, 9, menuPos == 9 ? MASKRED : MASKWHITE);
break;
case 1: //USB
Adafruit_GFX_drawColorBitmap(196, 91, bitmapUSB, 28, 9, menuPos == 9 ? MASKRED : MASKWHITE);
break;
case 2: //AM
Adafruit_GFX_drawColorBitmap(196, 91, bitmapAM, 28, 9, menuPos == 9 ? MASKRED : MASKWHITE);
break;
}
modeLast = mode;
}
if(afGain * 0.99 )
menuLastPos = menuPos;
displayUpdating = 0;
}
void drawWaterfall()
{
static float magnitudes[FFT_SIZE];
static float mags;
static uint8_t waterfallScanLine = 0;
unsigned short *gradient;
if(transmitting)
gradient = &bitmapIronGradient;
else
gradient = &bitmapWebSdrGradient;
arm_cmplx_mag_f32(samplesDisplay, magnitudes, FFT_SIZE);
float fftMax = 0; //AH! These are being reset each time! Static makes them persistant right? Does it also ensure they are
float fftMin = 100; //only initialized once? Have to try it when I get home. It would certainly be nice if the waterfall
static float fftMaxMax = 0; //didn't change in brightness so much. Later, I may want to fix these values, or at least, make them
static float logMax; //manually controllable, sorta, you know?
uint8_t i;
for(i = 1; i < 255; i++) //If bin 0 is the DC offset, should we skip it in this calculation?
{
float mags = magnitudes[i];
if(mags > fftMax) fftMax = mags;
if(mags < fftMin) fftMin = mags;
}
//logMax = log2(fftMax);
if(fftMax > fftMaxMax) fftMaxMax += fftMax * 0.1;
logMax = log2(fftMaxMax);
fftMaxMax *= 0.99;
if (fftMaxMax > fftMaxMaxMax) fftMaxMax = fftMaxMaxMax;
if (fftMaxMax < fftMaxMaxMin) fftMaxMax = fftMaxMaxMin;
// TODO: Got rid of the first bin because it's just DC offset, right?
// but now narrow signal can disappear when they are right at the center....
// Will that be better when I lower the sample frequency? Maybe I should do that next.
Adafruit_ILI9340_setAddrWindow(waterfallScanLine, 0, waterfallScanLine, 120);
for(i = 120; i != 0; i--)
{
mags = (log2(magnitudes[i] + 1)) / fftMaxMax * 100; //Log needs to be at least 1 right? We could do a + (1-fftMin) maybe? Worth it?
//mags = magnitudes[i] / fftMaxMax * 32;
//Adafruit_ILI9340_drawPixel(waterfallScanLine, (120 - i), gradient[(uint8_t) mags]);
Adafruit_ILI9340_pushColor(gradient[(uint8_t) mags]);
}
Adafruit_ILI9340_setAddrWindow(waterfallScanLine, 120, waterfallScanLine, 239);
for(i = 255; i > 135; i--)
{
mags = (log2(magnitudes[i] + 1)) / fftMaxMax * 100;
//mags = magnitudes[i] / fftMaxMax * 32;
//Adafruit_ILI9340_drawPixel(waterfallScanLine, 359 - (i - 15), gradient[(uint8_t) mags]);
Adafruit_ILI9340_pushColor(gradient[(uint8_t) mags]);
}
waterfallScanLine++;
if(waterfallScanLine > 119) waterfallScanLine = 0;
Adafruit_ILI9340_setVertialScrollStartAddress((/*119 -*/ waterfallScanLine) /*+ 200*/);
}
void fillSamepleWithTone(int tone, float *samples)
{
int i;
for(i = 0; i < FFT_BUFFER_SIZE; i++)
{
samples[i] = 0;
}
samples[tone] = 1;
}
void processStream()
{
if(sampleRun)
{
arm_cfft_radix4_instance_f32 fft_inst;
//blink_led_on();
if (sampleBankAReady == 1)
{
if(tone == 0)
{
arm_cfft_radix4_init_f32(&fft_inst, FFT_SIZE, 0, 1);
arm_cfft_radix4_f32(&fft_inst, samplesA);
// Calculate magnitude of complex numbers output by the FFT.
if(transmitting == 0)
{
if(waterfallBusy != 1)
{
uint16_t i;
for(i = 0; i < FFT_BUFFER_SIZE; i++) samplesDisplay[i] = samplesA[i];
}
}
applyCoeficient(samplesA, ifShift);
if(transmitting == 1)
{
if(waterfallBusy != 1)
{
uint16_t i;
for(i = 0; i < FFT_BUFFER_SIZE; i++) samplesDisplay[i] = samplesA[i];
}
}
} else {
fillSamepleWithTone(tone, samplesA);
}
arm_cfft_radix4_init_f32(&fft_inst, FFT_SIZE, 1, 1);
arm_cfft_radix4_f32(&fft_inst, samplesA);
if(mode == 2) //Try to demodulate AM
{
arm_cmplx_mag_f32(samplesA, samplesDemod, FFT_SIZE);
uint16_t i;
for(i = 0; i < FFT_SIZE; i++)
{
samplesA[i * 2] = samplesDemod[i];
samplesA[i * 2 + 1] = samplesDemod[i];
}
}
passBandRms = calculateRmsOfSample(samplesA, FFT_BUFFER_SIZE);
sampleBankAReady = 0;
}
else if(sampleBankBReady == 1)
{
if(tone == 0)
{
arm_cfft_radix4_init_f32(&fft_inst, FFT_SIZE, 0, 1);
arm_cfft_radix4_f32(&fft_inst, samplesB);
// Calculate magnitude of complex numbers output by the FFT.
//arm_cmplx_mag_f32(samplesB, magnitudes, FFT_SIZE);
applyCoeficient(samplesB, ifShift);
} else {
fillSamepleWithTone(tone, samplesB);
}
arm_cfft_radix4_init_f32(&fft_inst, FFT_SIZE, 1, 1);
arm_cfft_radix4_f32(&fft_inst, samplesB);
if(mode == 2) //Try to demodulate AM
{
arm_cmplx_mag_f32(samplesB, samplesDemod, FFT_SIZE);
uint16_t i;
for(i = 0; i < FFT_SIZE; i++)
{
samplesB[i * 2] = samplesDemod[i];
samplesB[i * 2 + 1] = samplesDemod[i];
}
}
passBandRms = calculateRmsOfSample(samplesB, FFT_BUFFER_SIZE);
sampleBankBReady = 0;
}
else if (sampleBankCReady == 1)
{
if(tone == 0)
{
arm_cfft_radix4_init_f32(&fft_inst, FFT_SIZE, 0, 1);
arm_cfft_radix4_f32(&fft_inst, samplesC);
// Calculate magnitude of complex numbers output by the FFT.
applyCoeficient(samplesC, ifShift);
} else {
fillSamepleWithTone(tone, samplesC);
}
arm_cfft_radix4_init_f32(&fft_inst, FFT_SIZE, 1, 1);
arm_cfft_radix4_f32(&fft_inst, samplesC);
if(mode == 2) //Try to demodulate AM
{
arm_cmplx_mag_f32(samplesC, samplesDemod, FFT_SIZE);
uint16_t i;
for(i = 0; i < FFT_SIZE; i++)
{
samplesC[i * 2] = samplesDemod[i];
samplesC[i * 2 + 1] = samplesDemod[i];
}
}
passBandRms = calculateRmsOfSample(samplesC, FFT_BUFFER_SIZE);
sampleBankCReady = 0;
}
//blink_led_off();
sampleRun = 0;
}
clearTimUpdateFlag(&TimHandle4);
}
void updateVfo()
{
encoderPos = getPos();
if(encoderPos != encoderLastPos)
{
vfoAFrequency += frequencyDialMultiplier * (encoderLastPos - encoderPos);
if(vfoAFrequency < 1) vfoAFrequency = 1;
if(vfoAFrequency > 37500000) vfoAFrequency = 37500000;
encoderLastPos = encoderPos;
}
if(vfoAFrequency != vfoALastFreq)
{
setFreq(vfoAFrequency);
}
}
void drawNumber(char c, uint16_t x, uint16_t y, uint16_t tintMask)
{
switch(c)
{
case '.':
Adafruit_GFX_drawColorBitmap(x, y, bitmapPeriod, 15, 19, tintMask);
break;
case '1':
Adafruit_GFX_drawColorBitmap(x, y, bitmapOne, 15, 19, tintMask);
break;
case '2':
Adafruit_GFX_drawColorBitmap(x, y, bitmapTwo, 15, 19, tintMask);
break;
case '3':
Adafruit_GFX_drawColorBitmap(x, y, bitmapThree, 15, 19, tintMask);
break;
case '4':
Adafruit_GFX_drawColorBitmap(x, y, bitmapFour, 15, 19, tintMask);
break;
case '5':
Adafruit_GFX_drawColorBitmap(x, y, bitmapFive, 15, 19, tintMask);
break;
case '6':
Adafruit_GFX_drawColorBitmap(x, y, bitmapSix, 15, 19, tintMask);
break;
case '7':
Adafruit_GFX_drawColorBitmap(x, y, bitmapSeven, 15, 19, tintMask);
break;
case '8':
Adafruit_GFX_drawColorBitmap(x, y, bitmapEight, 15, 19, tintMask);
break;
case '9':
Adafruit_GFX_drawColorBitmap(x, y, bitmapNine, 15, 19,tintMask);
break;
case '0':
Adafruit_GFX_drawColorBitmap(x, y, bitmapZero, 15, 19, tintMask);
break;
default:
Adafruit_GFX_fillRect(x, y, 15, 19, ILI9340_BLACK);
}
}
//TIM_TimeBaseInitTypeDef timeBaseStructure;
//
//TIM_OC_InitTypeDef tsConfig;
//#define PULSE1_VALUE 40961 /* Capture Compare 1 Value */
uint32_t uwPrescalerValue = 0;
//void TIM_setup()
//{
// /*##-1- Configure the TIM peripheral #######################################*/
// /* -----------------------------------------------------------------------
// In this example TIM3 input clock (TIM3CLK) is set to 2 * APB1 clock (PCLK1),
// since APB1 prescaler is different from 1.
// TIM3CLK = 2 * PCLK1
// PCLK1 = HCLK / 4
// => TIM3CLK = HCLK / 2 = SystemCoreClock /2
// To get TIM3 counter clock at 60 KHz, the Prescaler is computed as following:
// Prescaler = (TIM3CLK / TIM3 counter clock) - 1
// Prescaler = ((SystemCoreClock /2) /60 KHz) - 1
//
// Note:
// SystemCoreClock variable holds HCLK frequency and is defined in system_stm32f4xx.c file.
// Each time the core clock (HCLK) changes, user had to update SystemCoreClock
// variable value. Otherwise, any configuration based on this variable will be incorrect.
// This variable is updated in three ways:
// 1) by calling CMSIS function SystemCoreClockUpdate()
// 2) by calling HAL API function HAL_RCC_GetSysClockFreq()
// 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
// ----------------------------------------------------------------------- */
//
// /* Compute the prescaler value to have TIM3 counter clock equal to 60 KHz */
// uwPrescalerValue = (uint32_t) ((SystemCoreClock/2) / 60000) - 1;
//
// /* Set TIMx instance */
// TimHandle.Instance = TIM3; //TIMx;
//
// /* Initialize TIM3 peripheral as follow:
// + Period = 65535
// + Prescaler = (SystemCoreClock/2)/60000
// + ClockDivision = 0
// + Counter direction = Up
// */
// TimHandle.Init.Period = 65535;
// TimHandle.Init.Prescaler = uwPrescalerValue;
// TimHandle.Init.ClockDivision = 0;
// TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
// if(HAL_TIM_OC_Init(&TimHandle) != HAL_OK)
// {
// /* Initialization Error */
// //Error_Handler();
// doNothing();
// }
//
// /*##-2- Configure the PWM channels #########################################*/
// /* Common configuration */
// tsConfig.OCMode = TIM_OCMODE_TIMING;
// tsConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
// tsConfig.OCFastMode = TIM_OCFAST_DISABLE;
//
// /* Set the pulse value for channel 1 */
// tsConfig.Pulse = PULSE1_VALUE;
// if(HAL_TIM_OC_ConfigChannel(&TimHandle, &tsConfig, TIM_CHANNEL_1) != HAL_OK)
// {
// /* Initialization Error */
// //Error_Handler();
// doNothing();
// }
//
// /*##-4- Start the Output Compare mode in interrupt mode ####################*/
// /* Start Channel1 */
// if(HAL_TIM_OC_Start_IT(&TimHandle, TIM_CHANNEL_1) != HAL_OK)
// {
// /* Initialization Error */
// //Error_Handler();
// doNothing();
// }
//
//}
/////**
//// * @brief Configures the TIM IRQ Handler.
//// * @param None
//// * @retval None
//// */
//void TIM_Config(void)
//{
// NVIC_InitTypeDef NVIC_InitStructure;
//
// /* TIM3 clock enable */
// //RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
// __TIM3_CLK_ENABLE();
//
// /* Enable the TIM3 gloabal Interrupt */
// NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
// NVIC_Init(&NVIC_InitStructure);
//
//
//}
TIM_TypeDef timTimBase;
//TIM_HandleTypeDef timHandle;
/* Definition for TIMx's NVIC */
#define TIMx_IRQn 29 //TIM3_IRQn
#define TIMx_IRQHandler TIM3_IRQHandler
void TIM_Try(void)
{
uwPrescalerValue = (uint32_t) ((SystemCoreClock/2) / 21000000) - 1;
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
__TIM3_CLK_ENABLE();
TimHandle.Instance = TIM3;
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle.Init.Period = 1050;
TimHandle.Init.Prescaler = uwPrescalerValue;
TimHandle.Init.ClockDivision = 0;
HAL_TIM_Base_Init(&TimHandle);
HAL_TIM_Base_Start_IT(&TimHandle);
/*##-2- Configure the NVIC for TIMx #########################################*/
/* Set the TIMx priority */
HAL_NVIC_SetPriority(TIMx_IRQn, 0, 1);
/* Enable the TIMx global Interrupt */
HAL_NVIC_EnableIRQ(TIMx_IRQn);
__TIM4_CLK_ENABLE();
TimHandle4.Instance = TIM4;
TimHandle4.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle4.Init.Period = 1050;
TimHandle4.Init.Prescaler = uwPrescalerValue;
TimHandle4.Init.ClockDivision = 0;
HAL_TIM_Base_Init(&TimHandle4);
HAL_TIM_Base_Start_IT(&TimHandle4);
/*##-2- Configure the NVIC for TIMx #########################################*/
/* Set the TIMx priority */
HAL_NVIC_SetPriority(30 /*TIM4_IRQn*/, 2, 4);
/* Enable the TIMx global Interrupt */
HAL_NVIC_EnableIRQ(30 /*TIM4_IRQn*/);
// int tim3;
// while(1)
// {
// tim3 = timTryHandle.Instance->CNT;
// }
}
int ledState = 0;
HAL_TIM_PeriodElapsedCallback(htim)
{
captureSamples();
// doNothing();
// if(ledState)
// {
// blink_led_off();
// ledState = 0;
// }
// else
// {
// blink_led_on();
// ledState = 1;
// }
}
//void rectToPolar(float real, float imag, float mag, float angle)
//{
// mag = sqrtf((real * real) + (imag * imag));
// angle = atan2f(imag,real);
//}
//
//void polarToRect(float mag, float angle, float real, float imag)
//{
// real = mag * cosf(angle);
// imag = mag * sinf(angle);
//}
/* Definition for DACx clock resources */
#define DACx DAC
#define DACx_CLK_ENABLE() __DAC_CLK_ENABLE()
#define DACx_CHANNEL_GPIO_CLK_ENABLE() __GPIOA_CLK_ENABLE()
#define DACx_FORCE_RESET() __DAC_FORCE_RESET()
#define DACx_RELEASE_RESET() __DAC_RELEASE_RESET()
/* Definition for ADCx Channel Pin */
#define DACx_CHANNEL_PIN GPIO_PIN_4
#define DACx_CHANNEL_GPIO_PORT GPIOA
/* Definition for ADCx's Channel */
#define DACx_CHANNEL DAC_CHANNEL_1
DAC_HandleTypeDef DacHandle;
static DAC_ChannelConfTypeDef dacSConfig;
void initDac1()
{
DACx_CLK_ENABLE();
/*##-1- Configure the DAC peripheral #######################################*/
DacHandle.Instance = DACx;
if(HAL_DAC_Init(&DacHandle) != HAL_OK)
{
/* Initiliazation Error */
// Error_Handler();
doNothing();
}
/*##-2- Configure DAC channel1 #############################################*/
dacSConfig.DAC_Trigger = DAC_TRIGGER_NONE;
dacSConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
if(HAL_DAC_ConfigChannel(&DacHandle, &dacSConfig, DAC_CHANNEL_1) != HAL_OK)
{
/* Channel configuration Error */
// Error_Handler();
doNothing();
}
if(HAL_DAC_ConfigChannel(&DacHandle, &dacSConfig, DAC_CHANNEL_2) != HAL_OK)
{
/* Channel configuration Error */
// Error_Handler();
doNothing();
}
/*##-3- Set DAC Channel1 DHR register ######################################*/
if(HAL_DAC_SetValue(&DacHandle, DAC_CHANNEL_1, DAC_ALIGN_12B_R/*DAC_ALIGN_8B_R*/, 0x88) != HAL_OK)
{
/* Setting value Error */
// Error_Handler();
doNothing();
}
/*##-3- Set DAC Channel1 DHR register ######################################*/
if(HAL_DAC_SetValue(&DacHandle, DAC_CHANNEL_2, DAC_ALIGN_12B_R/*DAC_ALIGN_8B_R*/, 0x88) != HAL_OK)
{
/* Setting value Error */
// Error_Handler();
doNothing();
}
/*##-4- Enable DAC Channel1 ################################################*/
if(HAL_DAC_Start(&DacHandle, DAC_CHANNEL_1) != HAL_OK)
{
/* Start Error */
// Error_Handler();
doNothing();
}
/*##-4- Enable DAC Channel1 ################################################*/
if(HAL_DAC_Start(&DacHandle, DAC_CHANNEL_2) != HAL_OK)
{
/* Start Error */
// Error_Handler();
doNothing();
}
}
void dac1SetValue(uint16_t value)
{
value = value & 0b0000111111111111;
HAL_DAC_SetValue(&DacHandle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, value);
}
void dac2SetValue(uint16_t value)
{
value = value & 0b0000111111111111;
HAL_DAC_SetValue(&DacHandle, DAC_CHANNEL_2, DAC_ALIGN_12B_R, value);
}
#pragma GCC diagnostic pop
// ----------------------------------------------------------------------------