使用PIC32MX uc和SPI无法使我的DAC(PT8211)正常工作

时间:2019-06-07 20:07:07

标签: spi pic32

我只是想学习将PIC32MX534f06h与外部ADC和DAC(PT8211)配合使用。

到目前为止,我的代码仅是每次触发定时器中断时都使用ADC对信号进行采样,然后再将相同的信号发送到DAC。 中断和ADC部分可以正常工作,并且已经过独立测试,但是我的DAC输出对我的电压并没有太大的影响,并保持在2.5V(电源为0-5V)上。

我试图为DAC馈入从0到65534(16位DAC)的各种值,电压应该保持在2.5V,这应该是预期值。

我尝试使用不同的SPI(3和4)和DAC更改SPI配置(我将一个焊接到我的pcb,焊接到SPI3,以及一个焊接到SPI4的面包板,以防一个焊接到我的PCB上。板有缺陷)。 我确保芯片选择线按预期工作。 由于我还没有示波器,我看不到传输的数据和时钟。

我现在有点想法了。

芯片选择和SPI配置设置


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 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对数据进行采样,由Timer1触发。这很好。 ADC_input将数据输入到全局变量adc_value(12位,有符号)

//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);
 }

具有SPI,IO,计时器配置的主要功能

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){ 



  }
}

我希望看到DAC输出端的电压能够模仿输入到ADC输入端的电压,而无论我输入到ADC的是什么,DAC的输出值始终是恒定的

我想念什么? 另外,在打开SPI时,我是否仍应使用TRIS手动管理SDI SDO SCK引脚的IO配置,还是可以自动进行管理?

2 个答案:

答案 0 :(得分:0)

首先,我同意我最初为PT8211找到的文档很差。我找到了扩展文档here。您的DAC(PT8211)实际上是I2S设备,而不是SPI。 WS不是片选,而是字选择(左/右声道)。在I2S中,如果将WS设置为0,则表示左侧通道。但是,看起来在扩展数据表中,我发现WS 0实际上是正确的通道(如图)。

您所选择的PIC似乎没有任何I2S硬件,因此您可能需要对其进行一些测试。尽管有关I2S的信息很多,请参见I2S bus specification

SPI和I2C略有不同。请注意,第一位是当WS从高电平过渡到低电平时,是右通道的LSB。当WS从低变高时,它不是左通道的LSB。请注意,输出应介于0.4v至2.4v(I2S标准)之间,而不应介于0至5V之间。 (最大为2.5V,这就是您所看到的)。

I2S

I2S

基本上,我会先使用适当的协议并通过位冲击算法在左/右声道之间进行连续触发来进行尝试。

答案 1 :(得分:0)

首先,非常感谢您的评论。知道我不在考虑SPI传输,这很有帮助,这说明了为什么它不起作用。

一些反思

  • 我用Google搜索了bashing(猛击?),它似乎占用大量CPU,因此我将尽力避免
  • 我已经看到(成功的)projet(在MikroC中),其中有人使用SPI将数据从完全相同的PIC传输到相同的DAC,显然没有任何问题,所以我猜它应该以某种方式工作吗? 也许他正在转换数据以使其起作用?这是他正在使用的代码,我不确定F15位切换会发生什么,我想这是解决LSB移位问题的方法。这是我正在谈论的(有效)MikroC代码的一部分

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

据我了解,SPI和I2S之间的两个最大区别是SPI发送数据“突发”,而I2S则连续发送数据。另一个区别是,在字更改状态之后发送的数据是最后一个字的LSB。 所以我以为我的SPI是由一个计时器触发的,该计时器始终是相同的,因此即使数据不连续发送,它也会使声波更加``混叠'',并且如果它被足够定期地触发(例如(以44Mhz的频率),与以相同频率发送I2S数据应该没什么不同,对吧? 如果是这样,并且我正确理解,剩下的“唯一”问题就是管理LSB-下一个字-MSB位置问题,但是我认为LSB在16位值上实际上可以忽略不计,因此,如果我可以将我的位移位值右边,然后将LSB值固定为0或1,则误差很小,格式也正确。

听起来我有一个有效的“ Mc-Gyver-I2S-from-my-SPI”,还是我忘记了一些重要的东西?

到目前为止,我一直尝试实现它,但是没有成功,但是我不确定我的SPI配置是否正确,因此需要检查SPI配置

这是到目前为止的代码

SPI配置



       #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 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();
        }

我在这里发送的数据是有符号的,16位范围,我想您说这个DAC没问题,对吗?

或者我可以使用成帧的SPI?在这种模式下时钟似乎是连续的,但是我仍然要解决LSB MSB移位问题。

我在这里迷路了,所以任何帮助都会很酷