0

I want to convert a bunch of uint16_t values from an ADC into floating point voltages.

For this I use a for loop to loop through the uint16_t array and write the values to a float array.

But the float array remains 0 as if no assignment is ever made. Outside of the for loop the conversion works.

And when I step through the program with the debugger, I see reasonable float values but they do not end up being written to the array. Why?

the temporary float value is clearly 1.847: is clearly 1.847

the temporary array index is clearly 0: is clearly 0

so I expect the adc_voltages[0] to be 1.847 which it is not: which it is not

Code:

Global Variables:

volatile uint16_t adc_dma_buffer[SG_MK2_ADC1_CHANNELS * SG_MK2_ADC1_N_SAMPLES];
float adc_voltages[SG_MK2_ADC1_CHANNELS * SG_MK2_ADC1_N_SAMPLES];

Later in the main():

float temp = 0.0f;
    uint8_t index = 0;
    for(uint8_t i=0; i<8; i++){
        temp = BSP_convU1(adc_dma_buffer[i*SG_MK2_ADC1_CHANNELS+0]);
        index = i*SG_MK2_ADC1_CHANNELS+0;
        adc_voltages[index] = temp; // BSP_convU1(adc_dma_buffer[i*SG_MK2_ADC1_CHANNELS+0]);
        adc_voltages[i*SG_MK2_ADC1_CHANNELS+1] = BSP_convU2(adc_dma_buffer[i*SG_MK2_ADC1_CHANNELS+1]);
        adc_voltages[i*SG_MK2_ADC1_CHANNELS+2] = BSP_convU3(adc_dma_buffer[i*SG_MK2_ADC1_CHANNELS+2]);
        adc_voltages[i*SG_MK2_ADC1_CHANNELS+3] = BSP_internalTemperature(adc_dma_buffer[i*SG_MK2_ADC1_CHANNELS+3]);
    }

Where the functions return float:

float BSP_convU1(uint32_t adc_val){
    float adc_vsense = SG_MK2_ADC_VREF/4096.0f * (float)adc_val;
    return adc_vsense * BSP_CONV_U1_FACTOR + BSP_CAL_U1_OFFSET;
}

Edit:

Thanks for all the comments and good practice hints that I will use from now on. Especially with the usage of 2D arrays. I was just able to resolve the issue. I am still not sure why it happened. "working outside of the loop" was not correct either, it only worked, when BSP_conv_I_MPPT() was evaluated inside the printf statement directly.

Anyhow, the following code with 2D arrays now works.

if(flag_SDADC_cplt){
    flag_SDADC_cplt=0;
    for(int i=0; i<SG_MK2_SDADC1_N_SAMPLES; i++){
        adc_currents[i][0] = BSP_conv_I_Boost (sdadc_dma_buffer[i][0]);
        adc_currents[i][1] = BSP_conv_I_MPPT  (sdadc_dma_buffer[i][1]);
        adc_currents[i][2] = BSP_conv_I_Solar (sdadc_dma_buffer[i][2]);
        // order: adc[sample][channel]
    }
    printf("DCDC\tMPPT\tPV\n");
    printf("%.3fA\t%.3fA\t%.3fA\n", adc_currents[0][0], adc_currents[1][0], adc_currents[2][0]); // order[channel][sample]
}

if(flag_ADC_cplt){
    flag_ADC_cplt = 0;
    for(int i=0; i<SG_MK2_ADC1_N_SAMPLES; i++){
        adc_voltages[i][0] = BSP_convU1(adc_dma_buffer[i][0]);
        adc_voltages[i][1] = BSP_convU2(adc_dma_buffer[i][1]);
        adc_voltages[i][2] = BSP_convU3(adc_dma_buffer[i][2]);
        adc_voltages[i][3] = BSP_internalTemperature(adc_dma_buffer[i][3]);
    }
    printf("\nPV\tCAN\tBat\tTemp\n");
    printf("%.2fV\t%.2fV\t%.2fV\t%.1fC\n", adc_voltages[0][0], adc_voltages[0][1], adc_voltages[0][2], adc_voltages[0][3]);
}
mnemocron
  • 23
  • 1
  • 4
  • mnemocron, Better yet "But the float array remains 0 " is not shown by posted code. AFAIK, `SG_MK2_ADC1_N_SAMPLES` is amiss, printf of data is in error, debugger is buggy, etc. Best to post a [mcve]. – chux - Reinstate Monica Aug 14 '21 at 13:04
  • You're doing a log of array indexing "by hand", which is hard to read, confusing, and error prone. I'm guessing `SG_MK2_ADC1_CHANNELS` is 4. And I'm guessing `SG_MK2_ADC1_N_SAMPLES` is 8. If so, it would be slightly clearer to say `for(i=0; i< SG_MK2_ADC1_N_SAMPLES; i++)`. And you might think about making `adc_voltages`, at least, a two-dimensional array. (But neither of these changes are likely to change the behavior or solve the problem.) – Steve Summit Aug 14 '21 at 13:49
  • 1
    Also probably not your problem, but using `uint8_t` as an array index is a poor, unnecessary, and somewhat risky practice. I would declare both `index` and `i` as plain `int`. – Steve Summit Aug 14 '21 at 13:51
  • Switch to assembly level debugging and see what the code is actually doing in the assignment. Ensure all compiler optimisations are disabled. Your debugger display of `adc_voltages` is suspicious - being _global_ the array should be initialised to zero - _something_ has written to it or your runtime start-up is invalid. You also state "_float array remains 0_", which is clearly not the case. I strongly suggest [not using globals](https://www.embedded.com/a-pox-on-globals/) in any event. (or floating point for that matter). – Clifford Aug 14 '21 at 17:13
  • The code could be a great deal simpler and access faster is you simply used two dimensional arrays `[channel][sample]` rather than calculating the index position (repeatedly for an invariant expression too). – Clifford Aug 14 '21 at 17:22
  • @mnemocron **`Outside of the for loop the conversion works.`** what does it mean? – 0___________ Aug 15 '21 at 05:26
  • @mnemocron do you use this array? If not declare it `volatile` for the testing purposes – 0___________ Aug 15 '21 at 05:27
  • I edited the question in reply to the comments – mnemocron Aug 15 '21 at 07:03
  • it also might be clearer using arrays of `struct`s as well. based on your print statement the inner indexes have specific meanings, so just define a struct with the appropriate fields and you'd not need your "order: adc[sample][channel]" comment to explain which index refers to what – Sam Mason Aug 15 '21 at 08:23
  • @SamMason, I would not go with your structures, because you always would have to touch the implementation of an Adc Driver and your application(s), just because you want to reuse it somewhere else or with a different setting, The channel approach is much easier to reuse and reconfigure, That would also mean, the Adc Setup/Configuration is handled the same way. On some implementations you can not even directly access ADC values, you configure a sampling queue, feed this per DMA to the ADC and get the results streamed back per DMA. (e.g. 8 samples Chn1, 4 samples Chn2..) – kesselhaus Aug 16 '21 at 20:47
  • @kesselhaus my observation was also based on OP calling routines like `BSP_conv_I_Boost` which would seem to indicate that these aren't raw ADC values and could have some specific meaning to the code. naming things helps with understanding the code and changing structures should be easy. as always everything is a trade off! – Sam Mason Aug 17 '21 at 09:05

0 Answers0