Unexplained Conversion from a binary/hex within code - c

I am using code from the Waveshare website ( for use with the ADDA Waveshare board put on a RPi3 ) : http://www.waveshare.com/wiki/File:High-Precision-AD-DA-Board-Code.7z
*********************************************************************************************************
* name: main
* function:
* parameter: NULL
* The return value: NULL
*********************************************************************************************************
*/
int main()
{
uint8_t id;
int32_t adc[8];
int32_t volt[8];
uint8_t i;
uint8_t ch_num;
int32_t iTemp;
uint8_t buf[3];
if (!bcm2835_init())
return 1;
bcm2835_spi_begin();
bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_LSBFIRST ); // The default
bcm2835_spi_setDataMode(BCM2835_SPI_MODE1); // The default
bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_1024); // The default
bcm2835_gpio_fsel(SPICS, BCM2835_GPIO_FSEL_OUTP);//
bcm2835_gpio_write(SPICS, HIGH);
bcm2835_gpio_fsel(DRDY, BCM2835_GPIO_FSEL_INPT);
bcm2835_gpio_set_pud(DRDY, BCM2835_GPIO_PUD_UP);
//ADS1256_WriteReg(REG_MUX,0x01);
//ADS1256_WriteReg(REG_ADCON,0x20);
// ADS1256_CfgADC(ADS1256_GAIN_1, ADS1256_15SPS);
id = ADS1256_ReadChipID();
printf("\r\n");
printf("ID=\r\n");
if (id != 3)
{
printf("Error, ASD1256 Chip ID = 0x%d\r\n", (int)id);
}
else
{
printf("Ok, ASD1256 Chip ID = 0x%d\r\n", (int)id);
}
ADS1256_CfgADC(ADS1256_GAIN_1, ADS1256_15SPS);
ADS1256_StartScan(0);
ch_num = 8;
//if (ADS1256_Scan() == 0)
//{
//continue;
//}
while(1)
{
while((ADS1256_Scan() == 0));
for (i = 0; i < ch_num; i++)
{
adc[i] = ADS1256_GetAdc(i);
volt[i] = (adc[i] * 100) / 167;
}
for (i = 0; i < ch_num; i++)
{
buf[0] = ((uint32_t)adc[i] >> 16) & 0xFF;
buf[1] = ((uint32_t)adc[i] >> 8) & 0xFF;
buf[2] = ((uint32_t)adc[i] >> 0) & 0xFF;
printf("%d=%02X%02X%02X, %8ld", (int)i, (int)buf[0],
(int)buf[1], (int)buf[2], (long)adc[i]);
iTemp = volt[i]; /* uV */
if (iTemp < 0)
{
iTemp = -iTemp;
printf(" (-%ld.%03ld %03ld V) \r\n", iTemp /1000000, (iTemp%1000000)/1000, iTemp%1000);
}
else
{
printf(" ( %ld.%03ld %03ld V) \r\n", iTemp /1000000, (iTemp%1000000)/1000, iTemp%1000);
}
}
printf("\33[%dA", (int)ch_num);
bsp_DelayUS(100000);
}
bcm2835_spi_end();
bcm2835_close();
return 0;
}
Please help me figure out what this piece does in the main():
for (i = 0; i < ch_num; i++)
{
adc[i] = ADS1256_GetAdc(i);
volt[i] = (adc[i] * 100) / 167;
}
The constants (being 100 and 167) are not explained. What exactly are they trying to do in this 'calibration' and what do these constants depend upon?

Learning to read datasheets is an important skill for embedded programming.
The ADC on this chip returns a 24 bit signed value. The datasheet says
The ADS1255/6 full-scale input voltage equals ยฑ2VREF/PGA.
Full-scale is 0x7FFFFF or 8388607.
I believe VRef is 2.5V, and the code sets PGA to 1 with ADS1256_CfgADC(ADS1256_GAIN_1, ADS1256_15SPS);
So an adc[i] value of 1 represents 1/0x7FFFFF of (2*2.5/1)Volts or 0.596 microvolts. We can convert the raw reading to microvolts by multiplying by 5000000 / 8388607. By multiplying by a number that large would overflow a 32 bit int, so let's reduce.
5000000 / 8388607 ~= 500/839 ~= 100/167.
(It would be possible to get a little more precision without overflow by multiplying by 250/419)

Looking specifically at this piece of code (which seems to be the actual question
for (i = 0; i < ch_num; i++)
{
adc[i] = ADS1256_GetAdc(i);
volt[i] = (adc[i] * 100) / 167;
}
It reads a number of ADC channels (0 through ch_num-1) and then does a crude conversion of each ADC value to a percentage of 167.
Consider the way we normally do percentage calculations as (a/b)*100. In other words, work out what fraction a is of b and then multiply by 100. But with integer math, the initial division will yield zero for all values < b, and the multiply won't affect that.
So we rewrite (a/b)*100 as (a*100)/b. Now the division occurs after the multiply and you will get non-zero results.
More specifically consider this example
(100/167) * 100 should become 0.59 * 100 = 59%. But with integer math you get (100/167) * 100 = (0) * 100 = 0%. After the rewrite you have (100*100)/167 = (10000)/167 = 59.
This is a standard trick with integer math.

Related

how to create a simple iir low pass filter with not round errors? (16 bit pcm data)

i have an array of n length fullfilled by 16 bit (int16) pcm raw data,the data is in 44100 sample_rate
and stereo,so i have in my array first 2 bytes left channel then right channel etc...i tried to implement a simple low pass converting my array into floating points -1 1,the low pass works but there are round errors that cause little pops in the sound
now i do simply this :
INT32 left_id = 0;
INT32 right_id = 1;
DOUBLE filtered_l_db = 0.0;
DOUBLE filtered_r_db = 0.0;
DOUBLE last_filtered_left = 0;
DOUBLE last_filtered_right = 0;
DOUBLE l_db = 0.0;
DOUBLE r_db = 0.0;
DOUBLE low_filter = filter_freq(core->audio->low_pass_cut);
for(UINT32 a = 0; a < (buffer_size/2);++a)
{
l_db = ((DOUBLE)input_buffer[left_id]) / (DOUBLE)32768;
r_db = ((DOUBLE)input_buffer[right_id]) / (DOUBLE)32768;
///////////////LOW PASS
filtered_l_db = last_filtered_left +
(low_filter * (l_db -last_filtered_left ));
filtered_r_db = last_filtered_right +
(low_filter * (r_db - last_filtered_right));
last_filtered_left = filtered_l_db;
last_filtered_right = filtered_r_db;
INT16 l = (INT16)(filtered_l_db * (DOUBLE)32768);
INT16 r = (INT16)(filtered_r_db * (DOUBLE)32768);
output_buffer[left_id] = (output_buffer[left_id] + l);
output_buffer[right_id] = (output_buffer[right_id] + r);
left_id +=2;
right_id +=2;
}
PS: the input buffer is an int16 array with the pcm data from -32767 to 32767;
i found this function here
Low Pass filter in C
and was the only one that i could understand xd
DOUBLE filter_freq(DOUBLE cut_freq)
{
DOUBLE a = 1.0/(cut_freq * 2 * PI);
DOUBLE b = 1.0/SAMPLE_RATE;
return b/(a+b);
}
my aim is instead to have absolute precision on the wave,and to directly low pass using only integers
with the cost to lose resolution on the filter(and i'm ok with it)..i saw a lot of examples but i really didnt understand anything...someone of you would be so gentle to explain how this is done like you would explain to a little baby?(in code or pseudo code rapresentation) thank you
Assuming the result of function filter_freq can be written as a fraction m/n your filter calculation basically is
y_new = y_old + (m/n) * (x - y_old);
which can be transformed to
y_new = ((n * y_old) + m * (x - y_old)) / n;
The integer division / n truncates the result towards 0. If you want rounding instead of truncation you can implement it as
y_tmp = ((n * y_old) + m * (x - y_old));
if(y_tmp < 0) y_tmp -= (n / 2);
else y_tmp += (n / 2);
y_new = y_tmp / n
In order to avoid losing precision from dividing the result by n in one step and multiplying it by n in the next step you can save the value y_tmp before the division and use it in the next cycle.
y_tmp = (y_tmp + m * (x - y_old));
if(y_tmp < 0) y_new = y_tmp - (n / 2);
else y_new = y_tmp + (n / 2);
y_new /= n;
If your input data is int16_t I suggest to implement the calculation using int32_t to avoid overflows.
I tried to convert the filter in your code without checking other parts for possible problems.
INT32 left_id = 0;
INT32 right_id = 1;
int32_t filtered_l_out = 0; // output value after division
int32_t filtered_r_out = 0;
int32_t filtered_l_tmp = 0; // used to keep the output value before division
int32_t filtered_r_tmp = 0;
int32_t l_in = 0; // input value
int32_t r_in = 0;
DOUBLE low_filter = filter_freq(core->audio->low_pass_cut);
// define denominator and calculate numerator
// use power of 2 to allow bit-shift instead of division
const uint32_t filter_shift = 16U;
const int32_t filter_n = 1U << filter_shift;
int32_t filter_m = (int32_t)(low_filter * filter_n)
for(UINT32 a = 0; a < (buffer_size/2);++a)
{
l_in = input_buffer[left_id]);
r_in = input_buffer[right_id];
///////////////LOW PASS
filtered_l_tmp = filtered_l_tmp + filter_m * (l_in - filtered_l_out);
if(last_filtered_left < 0) {
filtered_l_out = last_filtered_left - filter_n/2;
} else {
filtered_l_out = last_filtered_left + filter_n/2;
}
//filtered_l_out /= filter_n;
filtered_l_out >>= filter_shift;
/* same calculation for right */
INT16 l = (INT16)(filtered_l_out);
INT16 r = (INT16)(filtered_r_out);
output_buffer[left_id] = (output_buffer[left_id] + l);
output_buffer[right_id] = (output_buffer[right_id] + r);
left_id +=2;
right_id +=2;
}
As your filter is initialized with 0 it may need several samples to follow a possible step to the first input value. Depending on your data it might be better to initialize the filter based on the first input value.

Does fmodf() cause a hardfault in stm32?

I am trying to create a modulated waveform out of 2 sine waves.
To do this I need the modulo(fmodf) to know what amplitude a sine with a specific frequency(lo_frequency) has at that time(t). But I get a hardfault when the following line is executed:
j = fmodf(2 * PI * lo_frequency * t, 2 * PI);
Do you have an idea why this gives me a hardfault ?
Edit 1:
I exchanged fmodf with my_fmodf:
float my_fmodf(float x, float y){
if(y == 0){
return 0;
}
float n = x / y;
return x - n * y;
}
But still the hardfault occurs, and when I debug it it doesn't even jump into this function(my_fmodf).
Heres the whole function in which this error occurs:
int* create_wave(int* message){
/* Mixes the message signal at 10kHz and the carrier at 40kHz.
* When a bit of the message is 0 the amplitude is lowered to 10%.
* When a bit of the message is 1 the amplitude is 100%.
* The output of the STM32 can't be negative, thats why the wave swings between
* 0 and 256 (8bit precision for faster DAC)
*/
static int rf_frequency = 10000;
static int lo_frequency = 40000;
static int sample_rate = 100000;
int output[sample_rate];
int index, mix;
float j, t;
for(int i = 0; i <= sample_rate; i++){
t = i * 0.00000001f; // i * 10^-8
j = my_fmodf(2 * PI * lo_frequency * t, 2 * PI);
if (j < 0){
j += (float) 2 * PI;
}
index = floor((16.0f / (lo_frequency/rf_frequency * 0.0001f)) * t);
if (index < 16) {
if (!message[index]) {
mix = 115 + sin1(j) * 0.1f;
} else {
mix = sin1(j);
}
} else {
break;
}
output[i] = mix;
}
return output;
}
Edit 2:
I fixed the warning: function returns address of local variable [-Wreturn-local-addr] the way "chux - Reinstate Monica" suggested.
int* create_wave(int* message){
static uint16_t rf_frequency = 10000;
static uint32_t lo_frequency = 40000;
static uint32_t sample_rate = 100000;
int *output = malloc(sizeof *output * sample_rate);
uint8_t index, mix;
float j, n, t;
for(int i = 0; i < sample_rate; i++){
t = i * 0.00000001f; // i * 10^-8
j = fmodf(2 * PI * lo_frequency * t, 2 * PI);
if (j < 0){
j += 2 * PI;
}
index = floor((16.0f / (lo_frequency/rf_frequency * 0.0001f)) * t);
if (index < 16) {
if (!message[index]) {
mix = (uint8_t) floor(115 + sin1(j) * 0.1f);
} else {
mix = sin1(j);
}
} else {
break;
}
output[i] = mix;
}
return output;
}
But now I get the hardfault on this line:
output[i] = mix;
EDIT 3:
Because the previous code contained a very large buffer array that did not fit into the 16KB SRAM of the STM32F303K8 I needed to change it.
Now I use a "ping-pong" buffer where I use the callback of the DMA for "first-half-transmitted" and "completly-transmitted":
void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef * hdac){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
for(uint16_t i = 0; i < 128; i++){
new_value = sin_table[(i * 8) % 256];
if (message[message_index] == 0x0){
dac_buf[i] = new_value * 0.1f + 115;
} else {
dac_buf[i] = new_value;
}
}
}
void HAL_DAC_ConvCpltCallbackCh1 (DAC_HandleTypeDef * hdac){
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
for(uint16_t i = 128; i < 256; i++){
new_value = sin_table[(i * 8) % 256];
if (message[message_index] == 0x0){
dac_buf[i] = new_value * 0.1f + 115;
} else {
dac_buf[i] = new_value;
}
}
message_index++;
if (message_index >= 16) {
message_index = 0;
// HAL_DAC_Stop_DMA (&hdac1, DAC_CHANNEL_1);
}
}
And it works the way I wanted:
But the frequency of the created sine is too low.
I cap at around 20kHz but I'd need 40kHz.
I allready increased the clock by a factor of 8 so that one is maxed out:
.
I can still decrease the counter period (it is 50 at the moment), but when I do so the interrupt callback seems to take longer than the period to the next one.
At least it seems so as the output becomes very distorted when I do that.
I also tried to decrease the precision by taking only every 8th sine value but
I cant do this any more because then the output does not look like a sine wave anymore.
Any ideas how I could optimize the callback so that it takes less time ?
Any other ideas ?
Does fmodf() cause a hardfault in stm32?
It is other code problems causing the hard fault here.
Failing to compile with ample warnings
Best code tip: enable all warnings. #KamilCuk
Faster feedback than Stackoverflow.
I'd expect something like below on a well enabled compiler.
return output;
warning: function returns address of local variable [-Wreturn-local-addr]
Returning a local Object
Cannot return a local array. Allocate instead.
// int output[sample_rate];
int *output = malloc(sizeof *output * sample_rate);
return output;
Calling code will need to free() the pointer.
Out of range array access
static int sample_rate = 100000;
int output[sample_rate];
// for(int i = 0; i <= sample_rate; i++){
for(int i = 0; i < sample_rate; i++){
...
output[i] = mix;
}
Stack overflow?
static int sample_rate = 100000; int output[sample_rate]; is a large local variable. Maybe allocate or try something smaller?
Advanced: loss of precision
A good fmodf() does not lose precision. For a more precise answer consider double math for the intermediate results. An even better approach is more involved.
float my_fmodf(float x, float y){
if(y == 0){
return 0;
}
double n = 1.0 * x / y;
return (float) (x - n * y);
}
Can I not use any function within another ?
Yes. Code has other issues.
1 value every 10uS makes only 100kSPS whis is not too much for this macro. In my designs I generate > 5MSPS signals without any problems. Usually I have one buffer and DMA in circular mode. First I fill the buffer and start generation. When the half transmition DMA interrupt is trigerred I fill the first half of the buffer with fresh data. The the transmition complete interrupt is trigerred I fill the second half and this process repeats all over again.

Return value not as expected. AVR C calculation

I am trying to perform the following calculation using an ATmega328P MCU.
๐‘๐‘œ๐‘ ๐‘–๐‘ก๐‘–๐‘œ๐‘› = 1000 ยท ๐‘‰๐‘Ž๐‘™0 + 2000 ยท ๐‘‰๐‘Ž๐‘™1 + โ‹ฏ + 8000 ยท ๐‘‰๐‘Ž๐‘™7 / ๐‘‰๐‘Ž๐‘™0+๐‘‰๐‘Ž๐‘™1+โ‹ฏ+๐‘‰๐‘Ž๐‘™7
In the main routine (as shown here):
int main(void)
{
//variables
uint16_t raw_values[8];
uint16_t position = 0;
uint16_t positions[8];
char raw[] = " raw";
char space[] = ", ";
char channelString[] = "Channel#: ";
char positionString[] = "Position: ";
//initialize ADC (Analog)
initADC();
//initialize UART
initUART(BAUD, DOUBLE_SPEED);
//give time for ADC to perform & finish 1st conversion
//8us x 25 = 200us
delay_us(200);
while(1)
{
//get the raw values from the ADC for each channel
for(uint8_t channel = 0; channel < 8; channel++)
{
raw_values[channel] = analog(channel);
//invert the raw value
raw_values[channel] = DIVISOR - raw_values[channel];
}
for(uint8_t channel = 0; channel < 8; channel++)
{
//print the channel#
transmitString(channelString);
printDec16bit(channel);
transmitString(space);
//print the raw value from the ADC conversion
printDec16bit(raw_values[channel]);
transmitString(raw);
transmitString(space);
//calculate the position value at each sensor
transmitString(positionString);
positions[channel] = (uint16_t)((POSITION_REF/DIVISOR) * raw_values[channel]);
printDec16bit(positions[channel]);
printCR();
}
printCR();
//calculate and display 'position'
position = calculatePosition(positions);
printDec16bit(position);
printCR();
printCR();
//add a delay
delay_ms(2000);
}
}
I am calling the following function, but the return value I am getting is way off.
uint16_t calculatePosition(uint16_t* channel_positions)
{
uint32_t intermediates[8];
uint32_t temp_sum = 0;
uint16_t divisor = 0;
uint16_t value = 0;
for(uint8_t i = 0; i < 8; i++)
{
intermediates[i] = channel_positions[i] * ((i + 1) * 1000);
}
for(uint8_t j = 0; j < 8; j++)
{
temp_sum = temp_sum + intermediates[j];
}
for(uint8_t k = 0; k < 8; k++)
{
divisor = divisor + channel_positions[k];
}
value = temp_sum/divisor;
return value;
}
Alternatively, I have even tried this code, and get a result that is not what I expect.
uint16_t calculatePosition(uint16_t* channel_positions)
{
uint16_t position;
position = ((1000 * channel_positions[0]) +
(2000 * channel_positions[1]) +
(3000 * channel_positions[2]) +
(4000 * channel_positions[3]) +
(5000 * channel_positions[4]) +
(6000 * channel_positions[5]) +
(7000 * channel_positions[6]) +
(8000 * channel_positions[7])) /
(channel_positions[0] +
channel_positions[1] +
channel_positions[2] +
channel_positions[3] +
channel_positions[4] +
channel_positions[5] +
channel_positions[6] +
channel_positions[7]);
return position;
}
What could I be doing wrong? For an array of values such as {15, 12, 5, 16, 11, 35, 964, 76} I expect a result of 6504, but instead I get a value in the 200's (or some other weird value).
Look at your input array: {15, 12, 5, 16, 11, 35, 964, 76}
Specifically, look at the element that is 964. That element times 7000 is 6748000 which is greater than a uint16_t can handle.
There are a number of solutions. One of them is changing to uint32_t. If this is not an option, you could extract a factor of 1000, like this:
position = 1000 *(
((1 * channel_positions[0]) +
(2 * channel_positions[1]) +
(3 * channel_positions[2]) +
(4 * channel_positions[3]) +
(5 * channel_positions[4]) +
(6 * channel_positions[5]) +
(7 * channel_positions[6]) +
(8 * channel_positions[7])) /
(channel_positions[0] +
channel_positions[1] +
channel_positions[2] +
channel_positions[3] +
channel_positions[4] +
channel_positions[5] +
channel_positions[6] +
channel_positions[7]));
Note that this will not eliminate the problem, but it could possibly reduce it so that the problem never occurs for reasonable input.
Taking the same idea to the loop version, we get:
uint16_t calculatePosition(uint16_t* channel_positions)
{
uint16_t temp_sum = 0;
uint16_t divisor = 0;
for(uint8_t i = 0; i < 8; i++) {
temp_sum += (channel_positions[i] * (i+1));
divisor += channel_positions[i];
}
return 1000*(temp_sum/divisor);
}
Note that you will lose some accuracy in the process due to rounding with integer division. Since you have been very careful with specifying the width, I assume you're not willing to change the type of the input array. This code should give you maximum accuracy with minimal extra memory usage. But if you're running this function often on a 16-bit machine it can impact performance quite a bit.
uint16_t calculatePosition(uint16_t* channel_positions)
{
// Use 32 bit for these
uint32_t temp_sum = 0;
uint32_t divisor = 0;
for(uint8_t i = 0; i < 8; i++) {
// Copy the value to a 32 bit number
uint32_t temp_pos = channel_positions[i];
temp_sum += temp_pos * (i+1);
divisor += temp_pos;
}
// Moved parenthesis for better accuracy
return (1000*temp_sum) / divisor;
}
Provided that the result can fit in a uint16_t there is absolutely zero chance that this version will fail, because the biggest possible value for 1000*temp_sum is 2,359,260,000 and the biggest value it can hold is 4,294,967,295.
Sidenote about MRE (minimal, reproducible example)
MRE:s are described here: https://stackoverflow.com/help/minimal-reproducible-example
In this example, a good main function to post in the question would be:
#include <stdio.h>
int main()
{
uint16_t positions[] = {15, 12, 5, 16, 11, 35, 964, 76};
uint16_t pos = calculatePosition(positions);
printf("%d\n", pos);
}
It's enough to demonstrate the problem you had and no more.
As it was said, the problem is in integer overflow.
Be careful when moving the multiplier outside, when using integer math! (A * 1000) / B does not equal to (A / B) * 1000.
The simplest solution, to convert first of operands in each operation into a wider type. Others will be converted implicitly. E.q.
...
position = ((1000UL * channel_positions[0]) +
(2000UL * channel_positions[1]) +
(3000UL * channel_positions[2]) +
(4000UL * channel_positions[3]) +
(5000UL * channel_positions[4]) +
(6000UL * channel_positions[5]) +
(7000UL * channel_positions[6]) +
(8000UL * channel_positions[7])) /
((uint32_t)channel_positions[0] +
channel_positions[1] + // no need to convert, it will be converted implicitly
channel_positions[2] + // since previous operand is wider
channel_positions[3] +
channel_positions[4] +
channel_positions[5] +
channel_positions[6] +
channel_positions[7]);

CMSIS FIR bandpass filter

I am trying to implement a 60kHz bandpass filter on the STM32F407 microcontroller and I'm having some issues. I have generated the filter with the help of MATLABs fdatool and then simulated it in MATLAB as well. The following MATLAB script simlates it.
% FIR Window Bandpass filter designed using the FIR1 function.
% All frequency values are in Hz.
Fs = 5250000; % Sampling Frequency
N = 1800; % Order
Fc1 = 59950; % First Cutoff Frequency
Fc2 = 60050; % Second Cutoff Frequency
flag = 'scale'; % Sampling Flag
% Create the window vector for the design algorithm.
win = hamming(N+1);
% Calculate the coefficients using the FIR1 function.
b = fir1(N, [Fc1 Fc2]/(Fs/2), 'bandpass', win, flag);
Hd = dfilt.dffir(b);
%----------------------------------------------------------
%----------------------------------------------------------
T = 1 / Fs; % sample time
L = 4500; % Length of signal
t = (0:L-1)*T; % Time vector
% Animate the passband frequency span
for f=55500:50:63500
signal = sin(2*pi*f*t);
plot(filter(Hd, signal));
axis([0 L -1 1]);
str=sprintf('Signal frequency (Hz) %d', f);
title(str);
drawnow;
end
pause;
close all;
signal = sin(2*pi*50000*t) + sin(2*pi*60000*t) + sin(2*pi*78000*t);
signal = signal / 3;
signal = signal(1:1:4500);
filterInput = signal;
filterOutput = filter(Hd,signal);
subplot(2,1,1);
plot(filterInput);
axis([0 4500 -1 1]);
subplot(2,1,2);
plot(filterOutput)
axis([0 4500 -1 1]);
pause;
close all;
From the fdatool I extract the filter co-efficents to 16-bit unsigned integers in q15 format, this because of the 12-bit ADC that I'm using. The filter co-efficents header that is generated by MATLAB is here and the resulting plot of the co-efficents can be seen in the following picture
Below is the code for the filter implementation which obviously isn't working and I don't really know what I can do differently, I've looked at some examples online Example 1 and Example 2
#include "fdacoefs.h"
#define FILTER_SAMPLES 4500
#define BLOCK_SIZE 900
static uint16_t firInput[FILTER_SAMPLES];
static uint16_t firOutput[FILTER_SAMPLES];
static uint16_t firState[NUM_TAPS + BLOCK_SIZE - 1];
uint16_t util_calculate_filter(uint16_t *buffer, uint32_t len)
{
uint16_t i;
uint16_t max;
uint16_t min;
uint32_t index;
// Create filter instance
arm_fir_instance_q15 instance;
// Ensure that the buffer length isn't longer than the sample size
if (len > FILTER_SAMPLES)
len = FILTER_SAMPLES;
for (i = 0; i < len ; i++)
{
firInput[i] = buffer[i];
}
// Call Initialization function for the filter
arm_fir_init_q15(&instance, NUM_TAPS, &firCoeffs, &firState, BLOCK_SIZE);
// Call the FIR process function, num of blocks to process = (FILTER_SAMPLES / BLOCK_SIZE)
for (i = 0; i < (FILTER_SAMPLES / BLOCK_SIZE); i++) //
{
// BLOCK_SIZE = samples to process per call
arm_fir_q15(&instance, &firInput[i * BLOCK_SIZE], &firOutput[i * BLOCK_SIZE], BLOCK_SIZE);
}
arm_max_q15(&firOutput, len, &max, &index);
arm_min_q15(&firOutput, len, &min, &index);
// Convert output back to uint16 for plotting
for (i = 0; i < (len); i++)
{
buffer[i] = (uint16_t)(firOutput[i] - 30967);
}
return (uint16_t)((max+min));
}
The ADC is sampling at 5.25 MSPS and it is sampling a 60kHz signal 4500 times and here you can see the Input to the filter and then the Output of the filter which is pretty weird..
Is there anything obvious that I've missed? Because I'm completely lost and any pointers and tips are helpful!
As Lundin pointed out I changed it to work with 32 bit integers instead and that actually solved my problem. Ofcourse I generated new filter co-efficents with MATLABS fdatool as signed 32 bit integers instead.
static signed int firInput[FILTER_SAMPLES];
static signed int firOutput[FILTER_SAMPLES];
static signed int firState[NUM_TAPS + BLOCK_SIZE -1];
uint16_t util_calculate_filter(uint16_t *buffer, uint32_t len)
{
uint16_t i;
int power;
uint32_t index;
// Create filter instance
arm_fir_instance_q31 instance;
// Ensure that the buffer length isn't longer than the sample size
if (len > FILTER_SAMPLES)
len = FILTER_SAMPLES;
for (i = 0; i < len ; i++)
{
firInput[i] = (int)buffer[i];
}
// Call Initialization function for the filter
arm_fir_init_q31(&instance, NUM_TAPS, &firCoeffs, &firState, BLOCK_SIZE);
// Call the FIR process function, num of blocks to process = (FILTER_SAMPLES / BLOCK_SIZE)
for (i = 0; i < (FILTER_SAMPLES / BLOCK_SIZE); i++) //
{
// BLOCK_SIZE = samples to process per call
//arm_fir_q31(&instance, &firInput[i * BLOCK_SIZE], &firOutput[i * BLOCK_SIZE], BLOCK_SIZE);
arm_fir_q31(&instance, &firInput[i * BLOCK_SIZE], &firOutput[i * BLOCK_SIZE], BLOCK_SIZE);
}
arm_power_q31(&firOutput, len, &power);
// Convert output back to uint16 for plotting
for (i = 0; i < (len); i++)
{
buffer[i] = (uint16_t)(firOutput[i] - 63500);
}
return (uint16_t)((power/10));
}

STM32F4 microcontroller serial wire debug not working

I am using the STM32F4 discovery board - http://www.st.com/st-web-ui/static/active/en/resource/technical/document/data_brief/DM00037955.pdf
And I am trying to debug via "printf"-like statements using the Serial Wire Viewer in the ST Micro STLink software: http://www.st.com/st-web-ui/static/active/en/resource/technical/document/user_manual/CD00262073.pdf
However I cannot see any results in my SWO Viewer despite setting the system clock to 168000000 Hz and stimulus port to 'All'. The (relevant) software I have running on the chip is below. This demo is set up to change the LED lights based on pressing the user button.
static uint8_t lastButtonStatus = RESET;
int main() {
init();
do {
loop();
} while (1);
}
void init() {
initLeds();
initButton();
}
void loop() {
static uint32_t counter = 0;
uint8_t currentButtonStatus = GPIO_ReadInputDataBit(GPIOA, USER_BUTTON);
if (lastButtonStatus != currentButtonStatus
&& currentButtonStatus != RESET) {
++counter;
GPIO_ResetBits(GPIOD, LEDS);
GPIO_SetBits(GPIOD, LED[counter % 4]);
// Test SWD output
SWV_puts("hello from stm32f4\n");
SWV_printfloat(1.98254, 2);
}
lastButtonStatus = currentButtonStatus;
}
Here are the SWV_ printing functions:
void SWV_puts(const char *s )
{
while (*s) ITM_SendChar(*s++);
}
/**
* #brief This function sends numbers to the serial wire viewer.
* #param number: number to be displayed on SWV
* #retval None
*/
void SWV_printnum(long number)
{
unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
unsigned int i = 0;
//if number is 0
if (number == 0)
{
ITM_SendChar('0'); //if number is zero
return;
}
//account for negative numbers
if (number < 0)
{
ITM_SendChar('-');
number = number * -1;
}
while(number > 0)
{
buf[i++] = number % 10; //display in base 10
number = number / 10;
//NOTE: the effect of i++ means that the i variable will be at number of digits + 1
}
for(; i > 0; i--)
{
ITM_SendChar((char)('0' + buf[i-1]));
}
}
/**
* #brief This function sends numbers to the serial wire viewer.
* #param number: number to be displayed on SWV
* #param digits: number of digits after decimal point
* #retval None
*/
void SWV_printfloat(double number, int digits)
{
int i = 0;
//handle negative numbers
if(number < 0.0)
{
ITM_SendChar('-');
number = -number;
}
//round correctly so that uart_printfloat(1.999, 2) shows as "2.00"
double rounding = 0.5;
for(i = 0; i < digits; ++i) rounding = rounding / 10.0;
number = number + rounding;
//extract the integer part of the number and print it
unsigned long int_part = (unsigned long) number;
double remainder = (double)(number - (double)int_part);
SWV_printnum(int_part); //print the integer part
if(digits > 0) ITM_SendChar('.'); //print decimal pint
int toprint;
while(digits-- > 0)
{
remainder = remainder * 10.0;
toprint = (int)remainder;
SWV_printnum(toprint);
remainder = remainder - toprint;
}
}
I can confirm that the code compiles with no errors or warnings.
I have tried your code (nothing else) on my STMF4-discovery and it works fine.
I think you have to update any thing to last version:
STM32 ST/LINK utility v3.4.0
STLinkUSBDriver.dll v4.3.3.0
ST-LINK_CLI.exe v2.0.0
STM32F4 discovery board ST-LINK Firmware version : V2J21S0
STLink dongle 1.1.0.0 (10/12/2013)
good luck

Resources