2024-07-04 11:31 PM
I would like to know if it is possible to generate a sweep signal (a sine wave with increasing frequency) using DAC with DIMA transfer and simultaneously sample it by ADC and store these ADC values in memory.
To generate the sweep signal, I use TIM2 as a DAC DMA trigger and consequently increase the prescaler value to change the frequency of the signal. Because I need a fixed ADC sampling rate, I cannot use the same timer to trigger ADC DMA, so TIM3 is used instead.
To synchronize two timers, I did the trick with master-slave timer synchronization, where TIM1 is a trigger source for TIM2 and TIM3. I thought, in this case, I could manage to generate the signal with DAC and start sampling it with ADC at the same.
However, what I also need is to save the sampled data to SD-card in csv files. I need at least 50 of such files and all of them should start from the beginning of the sweep. But because generation and sampling are hapenning in the background, all files contain the signal starting from a random moment (e.g. if the sweep signal starts from 100Hz, the csv file should contain values from 100Hz, but it may start recording from 355Hz).
So, is that possible to start the timers, wait until one period of the sweep signal is generated AND sampled (e.g. 100-800Hz), then maybe pause the timers until the data recording to csv file is done, and then start them again? I need to perform these steps around 50 times.
Here is my code:
DAC_ChannelConfTypeDef sConfig = { 0 }; // The sConfig is Defined Globally
double Fs = 100.0; //Chirp start frequency
double Ff = 800.0; //Chirp final freq
double Tc = 1.0; // Chirp Half Period [s]
double alpha = 0; // Frequency Sweep Rate [Hz/s]
double Cf = 0; // Maximum Allowable Frequency [Hz]
double deltat = 0; // Time Period of Wave [s]
double t = 0; // Time Variable [s]
double Ft = 0; // Wave Frequency Variable [Hz]
uint32_t MyClkFreq = 80000000; // Fixed APB1 Clock Frequency [Hz]
uint32_t MyPrescaler = 1 - 1; // Minimum Prescaler Value [cycles]
uint32_t MyPeriod = 80 - 1; // Fixed Period Value [cycles]
uint32_t data_size = 35;
uint32_t sine_val[data_size];
uint32_t accelRight[VIBRO_BUFFER_SIZE], accelLeft[VIBRO_BUFFER_SIZE];
float voltageR[VIBRO_BUFFER_SIZE], voltageL[VIBRO_BUFFER_SIZE];
#define VIBRO_BUFFER_SIZE 4096
#define SAMPLE_RATE 2000.0f
void get_sineval() {
for (int i = 0; i < data_size; i++) {
sine_val[i] = ((sin(i * 2 * PI / data_size) + 1) * (4096 / 2));
}
}
int main(void)
{
alpha = (Ff - Fs) / Tc / 2;
Cf = ((double) MyClkFreq / ((double) (MyPeriod + 1) * data_size));
HAL_TIM_Base_Start(&htim1);
HAL_TIM_Base_Start(&htim2);
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*) sine_val, data_size, DAC_ALIGN_12B_R);
HAL_TIM_Base_Start(&htim3);
HAL_ADC_Start_DMA(&hadc2, accelRight, VIBRO_BUFFER_SIZE);
HAL_ADC_Start_DMA(&hadc3, accelLeft, VIBRO_BUFFER_SIZE);
int num_files = 51;
int num_trial = 1;
while (1) {
while (num_trial != num_files) {
char filename[50];
sprintf(filename, "silicone40_100-800Hz_trial%d.csv", num_trial);
process_SD_card(filename);
printf("Trial %d done. \n", num_trial);
num_trial++;
}
HAL_DAC_Stop_DMA(&hdac, DAC_CHANNEL_1); // Stop the DAC Module in DMA Mode
HAL_TIM_Base_Stop(&htim2); // Stop the TIM Module
break;
}
}
void process_SD_card(const char *filename) {
FATFS FatFs;
FIL fil;
FRESULT fres;
char buf[100];
UINT bytesWritten;
do {
//Mount the SD Card
fres = f_mount(&FatFs, "", 1);
fres = f_open(&fil, filename, FA_WRITE | FA_CREATE_ALWAYS);
float timeStep = 1.0f / SAMPLE_RATE;
sprintf(buf, "Time (s), AccelRight Value, Time (s), AccelLeft Value\r\n");
fres = f_write(&fil, buf, strlen(buf), &bytesWritten);
for (int i = 0; i < VIBRO_BUFFER_SIZE / 1.8; i++) {
float timeR = i * timeStep;
float voltageR = ((accelRight[i] * 5.0f) / 4095.0f - 1.8)
/ 0.330; //0g bias level at Zout - see datasheet
float timeL = i * timeStep;
float voltageL = ((accelLeft[i] * 5.0f) / 4095.0f - 1.8)
/ 0.330; //0g bias level at Zout - see datasheet
sprintf(buf, "%.6f,%.6f, %.6f,%.6f\r\n", timeR, voltageR, timeL, voltageL);
fres = f_write(&fil, buf, strlen(buf), &bytesWritten);
}
}
f_close(&fil);
printf("Writing data to file completed!!!\r\n");
} while (false);
f_mount(NULL, "", 1);
CDtransfer_complete = true;
printf("SD Card Unmounted Successfully!!!\r\n");
}
void MY_TIM_UPDATE() {
htim2.Init.Prescaler = MyPrescaler;
HAL_TIM_Base_Init(&htim2);
}
void MY_DAC_UPDATE(void) {
MY_TIM_UPDATE();
deltat = (double) (((double) MyPrescaler + 1) / Cf);
// Update Time Variable [s]
(t > (2.0 * Tc)) ? (t = 0, Nchrip += 1) : (t += deltat);
Ft = (double) (Fs + alpha * t); // Update Frequency Variable
(Ft > Ff) ? (Ft = Ff) : 1; // Check Frequency Variable
(Ft > Cf) ? (Ft = Cf) : 1; // Check Frequency Variable
MyPrescaler = (uint32_t) ((Cf / Ft) - 1); // Compute Prescaler Value
}
void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef *hdac) {
MY_DAC_UPDATE();
}
Or maybe it is possible to save the required amount of sampled data in the memory and then run the SD function to save it in the respective files?
I am using STM32F407 Discovery board and STM32CubeIDE for programmming. Let me know if anything is unclear. Thank you!