我在 dsPIC33CK64MP505 上设置了 SPI2,以作为从机接收左调整音频。如果我通过轮询 SPI 缓冲区来运行代码,我会收到数据,一切都很顺利。不过,我需要左通道和右通道的同步,因此我试图让 SPI2 RX 中断在接收到的数据上触发。音频格式为 24 位左调整,因此 SPI2BUFH 包含 16 位 MSB,而 SPI2BUFL 包含最后 8 位 LSB。
我是这样配置的:
RPINR23bits.SS2R = 38; // RB6 LRCK
RPINR22bits.SCK2R = 39; // RB7 BCLK
RPINR22bits.SDI2R = 40; // RB8 ADCDAT (SDI)
IEC7bits.SPI2IE = 0;
SPI2CON1Lbits.SPIEN = 0;
SPI2CON1H = 0;
while(!SPI2STATLbits.SPIRBE) { (void) SPI2BUFL; (void) SPI2BUFH; }
SPI2STATLbits.SPIROV = 0; // Clear receive overflow
SPI2CON1Hbits.AUDMOD = 1; // Left justified
SPI2CON1Hbits.AUDEN = 1;
SPI2CON1Lbits.MSTEN = 0;
SPI2CON1Lbits.CKP = 0;
SPI2CON1Hbits.FRMPOL = 1;
SPI2CON1Lbits.MODE = 3; // 24bit over 32bit register
IPC7bits.SPI2RXIP = 4;
//SPI2IMSKHbits.RXMSK = 1; // Tried this as well
//SPI2IMSKHbits.RXWIEN = 1; // ...didn't work either
SPI2IMSKLbits.SPIRBFEN = 1;
IEC7bits.SPI2IE = 1;
//IFS7bits.SPI2IF = 0; // As a test, if I set this to 1,
// I enter the ISR instant.
SPI2CON1Lbits.ENHBUF = 1;
SPI2CON1Lbits.SPIEN = 1;
中断程序如下:
void __attribute__((interrupt, no_auto_psv)) _SPI2Interrupt(void) {
IFS7bits.SPI2IF = 0;
while(!SPI2STATLbits.SPIRBE) { // Clear buffer for test.
(void)(uint16_t)(SPI2BUFH);
(void)(uint8_t)(SPI2BUFL);
}
SPI2STATLbits.SPIROV = 0; // Clear receive overflow
}
因此,对于无错误的音频流,中断永远不会触发。如果我在初始化时设置 SPI2IF 标志,它会立即触发,因此 ISR 是正确的。我在轮询时获取数据,因此我们知道引脚配置正确。但由于某种原因,它不会在缓冲区已满事件上触发(我当然在尝试中断解决方案时不会进行轮询)。
我发现文档不清楚,甚至可能不完整(毫不奇怪,Microchip)。我启用了 SPI2IE 而不是 SPI2RXIE(IO 视图中也与 SPI2RXIF 一起丢失)。文档仅说明,相应地设置中断。
还必须使用增强型 SPI 缓冲模式。如果没有,我会在缓冲区中得到一些随机值,直到它们稳定并始终返回固定值。
缓冲区中的格式没有提到是右对齐的(它转换音频格式,因此 LSB 位于缓冲区的 LSB 中)。
所以我的左调整 24 位音频设置变成了这样:
RPINR23bits.SS2R = 38; // RB6 LRCK
RPINR22bits.SCK2R = 39; // RB7 BCLK
RPINR22bits.SDI2R = 40; // RB8 ADCDAT (SDI)
// Reset and clean-up
IEC7bits.SPI2IE = 0;
IEC1bits.SPI2RXIE = 0;
SPI2CON1Lbits.SPIEN = 0;
SPI2CON1H = 0;
while(!SPI2STATLbits.SPIRBE) { (void)SPI2BUFL; (void)SPI2BUFH; }
// Setup Left adjusted 24bit Audio
SPI2STATLbits.SPIROV = 0; // Clear receive overflow
SPI2CON1Hbits.AUDMOD = 1; // Left justified
SPI2CON1Hbits.AUDEN = 1; // Enable audio protocol
SPI2CON1Lbits.MSTEN = 0; // Listen in slave mode
SPI2CON1Lbits.CKP = 0; // Clock polarity for audio
SPI2CON1Hbits.FRMPOL = 1; // Set audio frame polarity
SPI2CON1Lbits.MODE = 3; // 24bit over 32bit register
SPI2CON1Hbits.IGNROV = 1; // Ignore buffer overrun
SPI2CON1Hbits.IGNTUR = 1; // Ignore buffer underrun
SPI2CON1Lbits.ENHBUF = 1; // Enable enhanced buffer mode (A MUST!)
SPI2IMSKLbits.SPIRBFEN = 1; // Rx Full interrupt Enable
IPC7bits.SPI2RXIP = 4; // Set interrupt priority
IFS1bits.SPI2RXIF = 0; // Clear Rx Interrupt flag
IEC1bits.SPI2RXIE = 1; // Enable Rx Interrupt
SPI2CON1Lbits.SPIEN = 1; // Enable SPI module
当然还需要设置另一个中断向量。
static uint32_t Levels[2] = { 0,0 }; // Right, Left channel
void __attribute__((interrupt, no_auto_psv)) _SPI2RXInterrupt(void) {
IFS1bits.SPI2RXIF = 0;
bool n = PORTBbits.RB6; // Get Left/Right channel
while(!SPI2STATLbits.SPIRBE) {
Levels[n] = SPI2BUFL;
Levels[n] += ((uint32_t)SPI2BUFH<<16);
}
}
这成功了。请注意,即使音频格式是左调整的,它在缓冲区中也是右调整的。请注意,24 位数据未进行符号扩展。您可以通过检查位 23 轻松完成此操作。
// Sign extend from 24bit to 32bit.
if(Levels[n]&0x00800000) Levels[n] |= 0xFF000000;
但是,SPI中有一点可以签名扩展,但我没有让它工作。 希望这能帮助其他尝试处理 Microchip 文档的人。