dsPIC33 SPI 音频中断未触发

问题描述 投票:0回答:1

我在 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 是正确的。我在轮询时获取数据,因此我们知道引脚配置正确。但由于某种原因,它不会在缓冲区已满事件上触发(我当然在尝试中断解决方案时不会进行轮询)。

interrupt audio-streaming spi microchip
1个回答
0
投票

我发现文档不清楚,甚至可能不完整(毫不奇怪,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 文档的人。

© www.soinside.com 2019 - 2024. All rights reserved.