Post Go back to editing

AD1938: what is the formula to transform the data received from AD1938 into volts?

I want to display a sine wave signal in a software program that I apply to the analog audio input of the codec. I get the data in the receive buffer, then convert it from a fixed-point format to a 32-bit floating-point format, but I do not know how to convert this data into an effective signal (amplitude in volts). Thank you.

  • Hello,

    The full-scale differential input for the AD1938 is listed as 1.9Vrms. To convert from digital amplitude to a voltage representation, you should just need to normalize a 100% FS signal to 1.9Vrms displayed in your software.



  • Hello Jerca,

    First you have to realize that it is just a number, it does not represent anything real outside of the digital world. First we have to assign some sort of standard to what full-scale is. The DAC is what assigns what the voltage will be. So a full scale number will produce a full scale voltage out of the DAC. In the case of the AD1938 the full scale voltage is 0.88V rms or 2.48Vp-p. Then you can divide this by the number of possible values, 2^24, to get the voltage of a single bit. So the same digital number will produce a different voltage out of different DACs depending on their internal reference.  

    For a 24 bit number that is in 2's compliment form,  the max number will be 0x7FF in hex for a positive number and 0x800 for a maximum negative number. Now this does not mean that the DAC will produce a negative voltage. Some do but many do not. Many DACs, the AD1938 included, have outputs raised up to a common mode voltage. This voltage will be the voltage of a zero in the data. So send out a 000 to the AD1938 and you will get 1.5V out of the DAC. A positive number into the DAC will produce a more positive voltage than 1.5V and a negative number sent to the DAC will produce a DC level less than 1.5V but never less than zero. Actually, I don't think it will be able to reach zero.

    So if you need to output DC out of the converter, you will need to reference the external Op-amps to the common mode voltage then translate it to what is required for the application.

    The same applies to the ADC side of things. Just as Tyler explained.

    I hope this helps.

    Dave T

  • So I use this configuration for AD1938:

    /* Setup the SPI parameters here in a buffer first */
    unsigned char ConfigParam1938[] = {
    (AD1938_ADDR),    CLKCTRL0,       DIS_ADC_DAC | INPUT256 | PLL_IN_MCLK | MCLK_OUT_OFF |                                                            PLL_PWR_DWN,
    (AD1938_ADDR),    DACCTRL0,       DAC_FMT_TDM | DAC_BCLK_DLY_1 | DAC_SR_48K,

    (AD1938_ADDR),    DACCTRL1,       DAC_LRCLK_POL_INV | DAC_BCLK_POL_INV | DAC_CHANNELS_8 |                                                                              DAC_LATCH_MID | DAC_BCLK_MASTER | DAC_LRCLK_MASTER,
    (AD1938_ADDR),    DACCTRL2,      DAC_WIDTH_24 | DAC_DEEMPH_32K,
    (AD1938_ADDR),    DACVOL_L1,    DACVOL_BEARABLE, /* Slot 4, Vout 1. */
    (AD1938_ADDR),    DACVOL_R1,   DACVOL_BEARABLE, /* Slot 5, Vout 5. */
    (AD1938_ADDR),    DACVOL_L2,    DACVOL_BEARABLE, /* Slot 6, Vout 2. */
    (AD1938_ADDR),    DACVOL_R2,    DACVOL_BEARABLE, /* Slot 7, Vout 6. */
    (AD1938_ADDR),    DACVOL_L3,    DACVOL_BEARABLE, /* Slot 0, Vout 3. */
    (AD1938_ADDR),    DACVOL_R3,   DACVOL_BEARABLE, /* Slot 1, Vout 7. */
    (AD1938_ADDR),    DACVOL_L4,    DACVOL_BEARABLE, /* Slot 2, Vout 4. */
    (AD1938_ADDR),    DACVOL_R4,    DACVOL_BEARABLE, /* Slot 3, Vout 8. */
    (AD1938_ADDR),    ADCCTRL0,       ADC_SR_48K,

    (AD1938_ADDR),    ADCCTRL2,       ADC_LRCLK_FMT_PULSE | ADC_BCLK_SLAVE | ADC_LRCLK_SLAVE |                                                            ADC_BCLK_SRC_INTERNAL | ADC_LRCLK_POL_INV | ADC_BCLK_POL_INV |                                                             ADC_CHANNELS_8,


    and in my firmware I use a falling edge interrupt on the TDM_FS (SPORT 2 for transmision SPORT 3 for reception).

    In the interrupt I change the ping-pong buffer then I undersample the signal (the sample rate of codec is 32 KHz and I want 1 KHz):

    if(g_analog_input_cntr == 32)
       g_analog_input_buffer[g_analog_input_state.sample_cntr_in] = g_analog_input_state.chL_mean / (float)0x20;
       g_analog_input_buffer[g_analog_input_state.sample_cntr_in + ANALOG_INPUT_CHANNEL_BUFFER_SIZE] =

                                              g_analog_input_state.chR_mean / (float)0x20;
       g_analog_input_state.chL_mean = 0;
       g_analog_input_state.chR_mean = 0;

       g_analog_input_cntr = 0;
       g_analog_input_state.sample_cntr_in = (g_analog_input_state.sample_cntr_in + 1) & ANALOG_INPUT_BUFFER_MASK;
       g_analog_input_state.chL_mean += (float)(*(rx_block_pointer[buffer_cntr]) << 8) / (float)(0x7FFFFFFF);
       g_analog_input_state.chR_mean += (float)(*(rx_block_pointer[buffer_cntr] + 1) << 8) / (float)(0x7FFFFFFF);

       //g_analog_input_state.chL_mean += __builtin_conv_RtoF(*(rx_block_pointer[buffer_cntr]));
       //g_analog_input_state.chR_mean += __builtin_conv_RtoF(*(rx_block_pointer[buffer_cntr] + 1));


    I want to transform the float values resulted from the fixed-point to floating-point conversion to amplitude values from the input sine wave. 

    What should I use for fixed-point to floating-point conversion? The __builtin_conv_RtoF() function or (float)(*(rx_block_pointer[buffer_cntr]) << 8) / (float)(0x7FFFFFFF)? Also, I use only IN1L and IN1R inputs so I should read only the first 2 slots of the rx buffer?

  • I just realised that the ADCs reads the output of DACs. If I send data to AD1938 (TDM_IN) I will recive the same data at TDM_OUT. In my system I use the DACs to send a signal from the MPU to the analog outputs and the ADCs to send to the MPU the signal from the analog inputs.

  • Hello Jerca,

    Something is wrong... You are setting the format of the ADC into the AUX mode. This will set it up for using external ADCs and DACs and the data pins change functions in the AUX modes.

    Look at table 13, Pin Function Changes in TDM and AUX modes and you will see the issue.

    You need to set the ADC in TDM mode if you are using only one codec. Even if you are using two codecs you would be daisy chaining them and not using the AUX modes.

    Regarding the code for setting up the serial ports and converting the numbers, you should ask that on the SHARC or BLACKFIN space on this forum since they can help answer those questions.

  • The problem is that if I set the ADC in TDM mode and DAC is in TDM mode, the TDM_OUT (ASDATA1) doesn`t output data (is always zero). If I set ADC in TDM mode and DAC in AUX mode, the TDM_OUT outputs the data from TDM_IN (the data that enters the DACs).

  • Hello jerca,

    Here is the table that shows what the pins are doing in the different modes.

    As you see in AUX modes, the ASDATA1 is the TDM Data Out but it is not the data you want.

    You have to use the standard TDM Mode where ASDATA1 will output the ADC data as a TDM signal. IF you are getting nothing out then something else is set wrong or the clocks are not correct coming into the ADC side of the part. These would be the ALRCLK and ABLCK.

    Dave T

  • Hi Dave,

       I resolved the problem by connecting ALRCLK to DLRCLK and putting the ADCs to TDM mode. Now I face another problem. 

        I apply to the analog input a signal (single ended - IN1L- connected to an analog GND, IN1L+ to a sin signal centered around 1.5 V of frequency 20 Hz and amplitude of 1 Vpp).

       The signal resulted from the data recived from ADCs has the same frequency and the same aplitude but it looks like that:

    The sample rate is 32 KHz.  I can't seem to find anything in documentation that might explain this behaviour.  Any help would be much appreciated.  Let me know if there's anything else I can post that might be useful information.