0
votes

I'm just trying to learn to use external ADC and DAC (PT8211) with my PIC32MX534f06h.

So far, my code is just about sampling a signal with my ADC every time a timer-interrupt is triggered, then sending then same signal out to the DAC. The interrupt and ADC part works fine and have been tested independently, but the voltages that my DAC outputs don't make much sens to me and stay at 2,5V (it's powered at 0 - 5V).

I've tried to feed the DAC various values ranging from 0 to 65534 (16bits DAC so i guess it should be the expected range of the values to feed to it, right?) voltage stays at 2.5V.

I've tried changing the SPI configuration, using different SPIs (3 and 4) and DACs (I have one soldered to my pcb, soldered to SPI3, and one one breadboard, linked to SPI4 in case the one soldered on my board was defective). I made sure that the chip selection line works as expected. I couldn't see the data and clock that are transmissed since i don't have a scope yet.

I'm a bit out of ideas now.

Chip selection and SPI configuration settings


signed short adc_value;
signed short DAC_output_value;
int Empty_SPI3_buffer;

#define Chip_Select_DAC_Set() {LATDSET=_LATE_LATE0_MASK;}
#define Chip_Select_DAC_Clr() {LATDCLR=_LATE_LATE0_MASK;}

#define SPI4_CONF 0b1000010100100000 // SPI on, 16-bit master,CKE=1,CKP=0   
#define SPI4_BAUD 100 // clock divider

DAC output function

//output to external DAC
void DAC_Output(signed int valueDAC) {
    INTDisableInterrupts();
    Chip_Select_DAC_Clr();
    while(!SPI4STATbits.SPITBE);    // wait for TX buffer to empty 
    SPI4BUF=valueDAC;               // write byte to TX buffer 
    while(!SPI4STATbits.SPIRBF);    // wait for RX buffer to fill 
    Empty_SPI3_buffer=SPI4BUF;      // read RX buffer 
    Chip_Select_DAC_Set();
    INTEnableInterrupts();
}

ISR sampling the data, triggered by Timer1. This works fine. ADC_input inputs the data in the global variable adc_value (12 bits, signed)

//ISR to sample data 
void __ISR( _TIMER_1_VECTOR, IPL7SRS) Test_data_sampling_in( void)
{
    IFS0bits.T1IF = 0;
    ADC_Input();
    //rescale the signed 12 bit audio values to unsigned 16 bits wide values
    DAC_output_value = adc_value + 2048;  //first unsign the signed 12 bit values (between 0 - 4096, center 2048)
    DAC_output_value = DAC_output_value *16;  // the scale between 12 and 16 bits is actually 16=65536/4096
    DAC_Output(DAC_output_value);
 }

main function with SPI, IO, Timer configuration

void main() {

    SPI4CON = SPI4_CONF; 
    SPI4BRG = SPI4_BAUD;

    TRISE = 0b00100000;
    TRISD = 0b000000110100;
    TRISG = 0b0010000000;

    LATD = 0x0;
    SYSTEMConfigPerformance(80000000L);  //
    INTCONSET = _INTCON_MVEC_MASK;    /* Set the interrupt controller for multi-vector mode */

//  
    T1CONbits.TON = 0;              /* turn off Timer 1 */
    T1CONbits.TCKPS = 0b11;            /* pre-scale = 1:1 (T1CLKIN = 80MHz (?) ) */
    PR1 = 1816;                    /* T1 period ~ ?  */
    TMR1 = 0;                       /* clear Timer 1 counter */
//    
    IPC1bits.T1IP = 7;              /* Set Timer 1 interrupt priority to 7 */
    IFS0bits.T1IF = 0;              /* Reset the Timer 1 interrupt flag */
    IEC0bits.T1IE = 1;               /* Enable interrupts from Timer 1 */
    T1CONbits.TON = 1;              /* Enable Timer 1 peripheral */

    INTEnableInterrupts();

    while (1){ 



  }
}

I would expect to see the voltage at the ouput of my DAC to mimic those I put at the input of my ADC, instead the DAC output value is always constant, no matter what I input to the ADC

What am i missing? Also, when turning the SPIs on, should I still manually manage the IO configuration of the SDI SDO SCK pins using TRIS or is it automatically taken care of?

2

2 Answers

0
votes

First of all I agree that the documentation I first found for PT8211 is rather poor. I found extended documentation here. Your DAC (PT8211) is actually an I2S device, not SPI. WS is not chip select, it is word select (left/right channel). In I2S, If you are setting WS to 0, that means the left channel. However it looks like in the extended datasheet I found that WS 0 is actually right channel (go figure).

The PIC you've chosen doesn't seem to have any I2S hardware so you might have to bit bash it. There is a lot of info on I2S though ,see I2S bus specification .

There are some slight differences with SPI and I2C. Notice that the first bit is when WS transitions from high to low is the LSB of the right channel. and when WS transitions from low to high, it is not the LSB of the left channel. Note that the output should be between 0.4v to 2.4v (I2S standard), not between 0 and 5V. (Max is 2.5V which is what you've been seeing).

I2S

I2S

Basically, I'd try it with the proper protocol first with a bit bashing algorithm with continuous flip flopping between a left/right channel.

0
votes

First of all, thanks a lot for your comment. It helps a lot to know that i'm not looking at a SPI transmission and that explains why it's not working.

A few reflexions about it

  • I googled Bit bashing (banging?) and it seems to be CPU intensive, which I would definately try to avoid
  • I have seen a (successful) projet (in MikroC) where someone transmit data from that exact same PIC, to the same DAC, using SPI, with apparently no problems whatsoever So i guess it SHOULD work, somehow? Maybe he's transforming the data so that it works? here is the code he's using, I'm not sure what happens with the F15 bit toggle, I was thinking that it was done to manage the LSB shift problem. Here is the piece of (working) MikroC code that i'm talking about

     valueDAC = valueDAC + 32768;
     valueDAC.F15 =~ valueDAC.F15;
     Chip_Select_DAC = 0;
     SPI3_Write(valueDAC);
     Chip_Select_DAC = 1;

From my understanding, the two biggest differences between SPI and I2S is that SPI sends "bursts" of data where I2S continuously sends data. Another difference is that data sent after the word change state is the LSB of the last word. So i was thinking that my SPI is triggered by a timer, which is always the same, so even if the data is not sent continuously, it will just make the sound wave a bit more 'aliased' and if it's triggered regularly enough (say at 44Mhz), it should not be SO different from sending I2S data at the same frequency, right? If that is so, and I undertand correctly, the "only" problem left is to manage the LSB-next-word-MSB place problem, but i thought that the LSB is virtually negligible over 16bit values, so if I could just bitshift my value to the right and then just fix the LSB value to 0 or 1, the error would be small, and the format would be right.

Does it sounds like I have a valid 'Mc-Gyver-I2S-from-my-SPI' or am I forgetting something important?

I have tried to implement it, so far without success, but I need to check my SPI configuration since i'm not sure that it's configured correctly

Here is the code so far

SPI config



       #define Chip_Select_DAC_Set() {LATDSET=_LATE_LATE0_MASK;}
        #define Chip_Select_DAC_Clr() {LATDCLR=_LATE_LATE0_MASK;}

        #define SPI4_CONF 0b1000010100100000
        #define SPI4_BAUD 20 

DAaC output function



      //output audio to external DAC
        void DAC_Output(signed int valueDAC) {
        INTDisableInterrupts();
        valueDAC = valueDAC  >> 1;  // put the MSB of ValueDAC 1 bit to the right     (becase the MSB of what is transmitted will be seen by the DAC as the LSB of the     last value, after a word select change)
        //Left channel
        Chip_Select_DAC_Set(); // Select left channel
        SPI4BUF=valueDAC; 
        while(!SPI4STATbits.SPITBE);    // wait for TX buffer to empty 
        SPI4BUF=valueDAC; // write 16-bits word to TX buffer 
        while(!SPI4STATbits.SPIRBF);    // wait for RX buffer to fill 
        Empty_SPI3_buffer=SPI4BUF;      // read RX buffer (don't know why we need to do     this here, but we do) 
        //SPI3_Write(valueDAC); MikroC option
        // Right channel
        Chip_Select_DAC_Clr(); 
        SPI4BUF=valueDAC; 
        while(!SPI4STATbits.SPITBE);    // wait for TX buffer to empty 
        SPI4BUF=valueDAC; // write 16-bits word to TX buffer 
        while(!SPI4STATbits.SPIRBF);    // wait for RX buffer to fill 
        Empty_SPI3_buffer=SPI4BUF;  
        INTEnableInterrupts();
        }

The data I send here is signed, 16 bits range, I think you said that it's allright with this DAC, right?

Or maybe i could use framed SPI? the clock seems to be continous in this mode, but I would still have the LSB MSB shifting problem to solve.

I'm a bit lost here, so any help would be cool