cancel
Showing results for 
Search instead for 
Did you mean: 

TouchGFX + CubeIDE Project (Gaussmetr/Oscillocope)

Thadeus
Associate

Hello,

I am working on a project using the STM32F429I-DISC1 board. This project is part of my part-time job and will also serve as my university thesis. I’ve been working on it for about a month, but I’ve run into some issues I can’t solve.

My goal is to make the board function somewhat like an oscilloscope (Gaussmeter) — it doesn’t need to be perfectly precise.
I’m sampling at 10 kHz and storing samples in a buffer of size 168 (since 10,000 / 60 ≈ 167.6). Every handleTickEvent() (which runs at 60 Hz), I send this buffer to a DynamicGraph.

The problem is that it doesn’t behave correctly.
In a previous version, I plotted one point per tick, which naturally skipped some samples but still displayed the sine wave correctly on the DynamicGraph, and the computed values were accurate.

In this new version, I’m trying to buffer 168 samples and then plot them in a for loop, but the results are inconsistent:

  • sometimes nothing is drawn,

  • sometimes the same Y value repeats for many X values, and calculated values Peak and Mean are stucked

  • and only around 130 Hz does it start resembling a sine wave.

I would really appreciate any help.
The main goal is to buffer the ADC samples and display them correctly on the graph. I need at least a 4 kHz sampling frequency.

main.c

 
#define ADC_BUFFER 168

__IO uint16_t rawValues[ADC_BUFFER];

__IO uint16_t voltages[ADC_BUFFER];



volatile bool halfReady = false;

volatile bool fullReady = false;



void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)

{

for (uint16_t i = 0; i < ADC_BUFFER/2; i++)

{

voltages[i] = rawValues[i] * 3300 / 4095;

}

}



void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)

{

for (uint16_t i = ADC_BUFFER/2; i < ADC_BUFFER; i++)

{

voltages[i] = rawValues[i] * 3300 / 4095;

}

}





//ADC1 and Timer1

HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);

HAL_ADC_Start_DMA(&hadc1, (uint32_t *)rawValues, ADC_BUFFER);





Screen1View.cpp





#include <gui/screen1_screen/Screen1View.hpp>





#include <cmath> // sin() a M_PI

#include <cstdlib> // rand()



#ifdef SIMULATOR

#include <cstdint>

#else

#include "stm32f4xx_hal.h"

#endif



constexpr int ADC_BUFFER = 168;

#ifndef SIMULATOR

extern __IO uint16_t voltages[ADC_BUFFER];

#endif





Screen1View::Screen1View()

{



}



void Screen1View::setupScreen()

{

Screen1ViewBase::setupScreen();



textArea1.setWildcard(textArea1Buffer);

textArea2.setWildcard(textArea2Buffer);

}



void Screen1View::tearDownScreen()

{

Screen1ViewBase::tearDownScreen();

}



void Screen1View::handleTickEvent()

{

#ifdef SIMULATOR

static float phase = 0.0f;

const float step = 2.0f * M_PI / 100.0f;

const float amplitude = 1650.0f;

const float offset = 1650.0f;



for (uint16_t i = 0; i < 100; i++)

{

uint16_t value = static_cast<uint16_t>(offset + amplitude * sin(phase));

modelListener->UpdateGraph1(value);

phase += step;

if (phase >= 2.0f * M_PI)

phase -= 2.0f * M_PI;

}

#else



float sum = 0.0f;

float peak = -1000000.0f;



for (uint16_t i = 0; i < ADC_BUFFER; i++)

{

dynamicGraph1.addDataPoint(voltages[i]);



if (voltages[i] > peak)

peak = voltages[i];



sum += voltages[i];



}



float mean = sum / ADC_BUFFER;



Unicode::snprintfFloat(textArea2Buffer, TEXTAREA2_SIZE, "%6.2f", mean);

textArea2.resizeToCurrentText();

textArea2.invalidate();



Unicode::snprintfFloat(textArea1Buffer, TEXTAREA1_SIZE, "%6.2f", peak);

textArea1.resizeToCurrentText();

textArea1.invalidate();

#endif

}

Maybe I am doing something wrong. I checked a lot of other threads and I saw a lot of videos but its always just simple tasks not buffering frequencies like that. But I think it shouldnt be that hard to do. I must be missing something important.

2 REPLIES 2
JohanAstrup
ST Employee

Hello @Thadeus.

If you haven't seen it already, I recommend you to have a look at the HVAC IoT Demo available in TouchGFX Designer. In the demo, a buffer is used to store the graph data. However, I cannot guarantee that you will find it useful, as multiple points are only added during initialization of the graph and when you change the selected room.

Is your project running on the Disco board without any additional hardware? If so, could you share your project so I can try to replicate the issue?

Best regards,
Johan


@Thadeus wrote:

I’m sampling at 10 kHz and storing samples in a buffer of size 168 (since 10,000 / 60 ≈ 167.6). Every handleTickEvent() (which runs at 60 Hz), I send this buffer to a DynamicGraph.

That buffer is too small if any part of your processing code is blocking or if handleTickEvent can be late. Unless you want to lose samples. You can use a double buffer or a circular buffer to be sure. 

 


@Thadeus wrote:

In this new version, I’m trying to buffer 168 samples and then plot them in a for loop, but the results are inconsistent:

  • sometimes nothing is drawn,

  • sometimes the same Y value repeats for many X values, and calculated values Peak and Mean are stucked

  • and only around 130 Hz does it start resembling a sine wave.

My advice is to get this display part to first work in the simulator. If it doesn't work in the simulator it won't work on your target either. You can simple create dummy values at the beginning of handleTickEvent() if the simulator is used.

#ifdef SIMULATOR
//put dummy values in buffer
#endif

// process buffer

 

You can also do the opposite: test the ADC-part without the TouchGFX part. You can send the samples via UART instead of to DynamicGraph. Just send them in binary at a high bitrate to make sure your UART has enough bandwidth.

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.