我只是想学习将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配置,还是可以自动进行管理?
答案 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,这就是您所看到的)。
基本上,我会先使用适当的协议并通过位冲击算法在左/右声道之间进行连续触发来进行尝试。
答案 1 :(得分:0)
首先,非常感谢您的评论。知道我不在考虑SPI传输,这很有帮助,这说明了为什么它不起作用。
一些反思
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移位问题。
我在这里迷路了,所以任何帮助都会很酷