2024-07-09 07:22 PM
Hello Everyone,
Problem: I am working with a instrument where we frequently get the problem of frequency drop out, i.e. suddenly frequency signal goes missing i.e. goes to zero, this cause the loss in data as shown in the below image. Yellow is received frequency signal from Photodetector and Purple is the demodulated data (our desire output). When frequency goes zero the purple line is constant so data is lost.
Solution:
In order to solve this problem, I have solution in my mind, i.e. I should develop an algorithm which could work as follow,
In this case I will have two Analog Inputs F_A, F_B and one analog output A_out.
// F_A is our sensor data
// Based on F_A, F_B is our final result obtained by demodulation of F_A.
I want to developed following logic
When data is not missing (i.e. F_A is not zero then output (A_out) of microprocessor should be zero, while F_B should store in the buffer zone.
If F_A =0 is detected then the output (A_out) should be the (F_B stored in buffer zone) i.e. I want to utilize the previous value of F_B when F_A was not zero.
As a visualization: Look at picture
Yellow (F_A) will be continuously monitored, Purple (F_B) should be store in buffer zone. As can be seen rectangular point yellow goes zero and purple become constant, so this constant purple gap should be filled by buffer zone.
P.S I am Mechanical Engineering Student and I never had programming experience with MCU, I just used arduino once in my life. So, I developed a code with ChatGPT but it's giving me error, The code is of 250+ lines but my logic part is just of 10-20 lines starting from line 115 to 137
Sincerely.
Umair
//After providing a lot of errors and my code in main.c file this code is directly copied from chat-gpt
//Instead of using main.c I can use this main2.c file for further developments
// All the errors are resolved with ChatGPT and internet search. So, use main2c file for further developement of your work.
#include "stm32f4xx.h"
#include "stm32f4xx_hal.h"
#include "stm32f4xx_hal_conf.h"
#include "stm32f4xx_hal_rcc.h"
#include "stm32f4xx_hal_adc.h"
#include "stm32f4xx_hal_dma.h"
#include "stm32f4xx_hal_gpio.h"
#include "stm32f4xx_hal_dac.h"
#include "stm32f4xx_hal_tim.h"
#include "stm32f4xx_hal_rcc_ex.h"
#include "stm32f4xx_hal_adc_ex.h"
#include "stm32f4xx_hal_dma_ex.h"
#include "stm32f4xx_hal_gpio_ex.h"
#include "stm32f4xx_hal_dac_ex.h"
#include "stm32f4xx_hal_tim_ex.h"
#define BUFFER_SIZE 1000 // Adjust buffer size as needed
uint16_t F_B_Buffer[BUFFER_SIZE]; // This will store pulses when frequency is greater than zero
uint16_t Verification_Buffer[BUFFER_SIZE]; // This will store pulses when frequency is zero
volatile int F_B_Index = 0; // This will initialize it to 0. Volatile means value may change
volatile int Ver_Index = 0; // This will initialize it to 0. Ver means it will track the verification buffer
volatile int F_A_Val = 0; // This will initialize it to 0. This will hold the frequency values
ADC_HandleTypeDef hadc1;
DAC_HandleTypeDef hdac;
TIM_HandleTypeDef htim2;
void Error_Handler(void)
{
// User can add their own implementation to report the HAL error return state
while(1)
{
}
}
void ADC_Config(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
// Common config
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
// Initialization Error
Error_Handler();
}
// Configure for the selected ADC regular channel
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
// Channel Configuration Error
Error_Handler();
}
}
void DAC_Config(void)
{
DAC_ChannelConfTypeDef sConfig = {0};
hdac.Instance = DAC;
if (HAL_DAC_Init(&hdac) != HAL_OK)
{
// Initialization Error
Error_Handler();
}
sConfig.DAC_Trigger = DAC_TRIGGER_NONE;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
if (HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1) != HAL_OK)
{
// Channel configuration Error
Error_Handler();
}
}
void SystemClock_Config(void);
void ADC_Config(void);
void DMA_Config(void);
void GPIO_Config(void);
void TIM_Config(void);
void DAC_Config(void);
int main(void)
{
HAL_Init(); // This function initialize the Hardware Abstraction Layer
SystemClock_Config(); // This function configures the system clock.
ADC_Config(); // This function configures the ADC (Analog-to-Digital Converter)
DMA_Config(); // This function configures the DMA (Direct Memory Access)
GPIO_Config(); // This function configures the GPIO (General-Purpose Input/Output) pins
TIM_Config(); // This function configures the timers.
DAC_Config(); // This function configures the DAC (Digital-to-Analog Converter)
while (1)
{
if (F_A_Val > 0)
{
// Step 1: F_A > 0, store F_B in buffer
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&F_B_Buffer[F_B_Index], 1);
F_B_Index = (F_B_Index + 1) % BUFFER_SIZE;
// Analog output A_out = 0
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
}
else
{
// Step 2: F_A == 0, output F_B from buffer
for (int i = 0; i < BUFFER_SIZE; i++)
{
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, F_B_Buffer[i]);
HAL_Delay(1); // Adjust delay for correct timing
}
// Store current F_B for verification
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&Verification_Buffer[Ver_Index], 1);
Ver_Index = (Ver_Index + 1) % BUFFER_SIZE;
}
}
}
void DMA_Config(void)
{
// DMA Initialization
__HAL_RCC_DMA2_CLK_ENABLE();
DMA_HandleTypeDef hdma_adc1;
hdma_adc1.Instance = DMA2_Stream0;
hdma_adc1.Init.Channel = DMA_CHANNEL_0;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_adc1);
__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
}
void GPIO_Config(void)
{
// GPIO Initialization
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void TIM_Config(void)
{
// Timer Initialization
TIM_HandleTypeDef htim2;
__HAL_RCC_TIM2_CLK_ENABLE();
htim2.Instance = TIM2;
htim2.Init.Prescaler = 84 - 1; // 1 MHz frequency
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 1000 - 1; // 1 kHz update rate
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
// Initialization Error
Error_Handler();
}
if (HAL_TIM_Base_Start_IT(&htim2) != HAL_OK)
{
// Starting Error
Error_Handler();
}
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
}
void TIM2_IRQHandler(void)
{
// Timer interrupt handler
if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_UPDATE) != RESET)
{
if (__HAL_TIM_GET_IT_SOURCE(&htim2, TIM_IT_UPDATE) != RESET)
{
__HAL_TIM_CLEAR_IT(&htim2, TIM_IT_UPDATE);
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
F_A_Val = HAL_ADC_GetValue(&hadc1);
}
}
}
2024-07-10 07:08 PM
How do you get the digital signal from the analog signal?
It looks to me, you use a digital input, e.g. with a Schmitt Trigger.
This works fine until the analog signal amplitude drops below a threshold. Therefore, you get this "strange" constant digital signal (the Schmitt-Trigger will not trigger or flips into other state without a chance to come back, hysteresis is too small).
You could add an external amplifier to increase the values during this period where you do not have a signal (it is too small for your input, Schmitt Trigger).
BTW: why does your signal drops below a threshold?
You could also try to sample this signal as real analog, with an ADC. Now you might see that the amplitude of your signal goes below a minimum threshold. Potentially, you can see still a waveform with low amplitudes (but based on your scope picture it looks to me more like "there is not a signal anymore, just noise").
Before starting with some SW work arounds - check your external signal:
I think, you get in a region for your sensor cannot provide anymore correct (reliable) data. There is not any solution in SW or HW (just to change to a different sensor with other characteristics).
2024-07-11 05:39 AM
So, I want to solve that issue using the SW as I explained above.