
Проблема - на плате стоит кодек AD73322l, подключен по SSC к SAM7X.
SSC работает в слейв-режиме, клокится от кодека.
Кодек двухканальный, формат данных потока ...[ 16 bit канал 1 ][ 16 bit канал 2 ]...
Проблема в том, что после некоторого времени работы теста (10-30 минут) SSC передатчик теряет один фрейм и каналы на выходе кодека "меняются местами". Через некоторое время ситуается повторяется и все возвращается в норму.
Приемник всегда работает четко.
Работаю через DMA, переключение буферов в прерывании.
Проверка времени реакции на прерывание, чтение свежей errata, различные телодвижения с бубном и выключением SPORT интерфейса кодека результата не дали.
Проблему удалось (тьфу-тьфу-тьфу) решить (тьфу-тьфу-тьфу) только сбросом (SWRST) и переинициализацией SSC модуля при каждом входе в прерывание.
Еще раз тьфу-тьфу-тьфу, ибо ловить такой баг в тестовой стойке с платами - занятие, несомненно, интересное, но крайне выматывающее...

Вот код рабочего обработчика :
Код
__arm void PSSC_InterruptHandler(void)
{
unsigned long STATUS = AT91C_BASE_SSC->SSC_SR;
///////// //////////////////
// first, updating buffer count
if (sscProcessor->mainBuffer == FIRST_BUFFER)
{
sscProcessor->mainBuffer = SECOND_BUFFER;
sscProcessor->shadowBuffer = FIRST_BUFFER;
}
else
{
sscProcessor->mainBuffer = FIRST_BUFFER;
sscProcessor->shadowBuffer = SECOND_BUFFER;
}
if (STATUS & AT91C_SSC_RXBUFF)
{
#ifdef SSC_ENABLE_IRQ_RESETS_SSC
__SSC_PeripheryInit();
// forcibly enable IRQ
AT91C_BASE_SSC->SSC_IER = AT91C_SSC_ENDRX | AT91C_SSC_RXBUFF;
#endif
// we've lost both buffers, need to reprogram all and to restart transfer
// restarting Xchange
// disable transmitter and PDC
#ifdef SSC_ENABLE_IRQ_RESETS_SSC
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXDIS | AT91C_SSC_TXDIS;
#endif
AT91C_BASE_SSC->SSC_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
//
unsigned short read = AT91C_BASE_SSC->SSC_RHR; // reading that shit for SSC clears itself
read = AT91C_BASE_SSC->SSC_RHR; // reading that shit !
read = AT91C_BASE_SSC->SSC_RHR; // reading that shit !
// current TX buffer
AT91C_BASE_SSC->SSC_TPR = (unsigned long)(sscProcessor->TXbuffers[ sscProcessor->mainBuffer ]);
AT91C_BASE_SSC->SSC_TCR = sscProcessor->buffersLength;
// current RX buffer
AT91C_BASE_SSC->SSC_RPR = (unsigned long)(sscProcessor->RXbuffers[ sscProcessor->mainBuffer ]);
AT91C_BASE_SSC->SSC_RCR = sscProcessor->buffersLength;
// starting RC/TM
AT91C_BASE_SSC->SSC_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
#ifdef SSC_ENABLE_IRQ_RESETS_SSC
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN;
#endif
// posting semaphore to signal codec 'bout buffers switched
OSSemPost( sscProcessor->buffersSwitchSemaphore );
}
/////////////////////////// /////////////////////////// ///////////////////////////
AT91C_BASE_AIC->AIC_IVR = 0;
AT91C_BASE_AIC->AIC_ICCR = (1 << AT91C_ID_SSC);
AT91C_BASE_AIC->AIC_EOICR = 0;
}
{
unsigned long STATUS = AT91C_BASE_SSC->SSC_SR;
///////// //////////////////
// first, updating buffer count
if (sscProcessor->mainBuffer == FIRST_BUFFER)
{
sscProcessor->mainBuffer = SECOND_BUFFER;
sscProcessor->shadowBuffer = FIRST_BUFFER;
}
else
{
sscProcessor->mainBuffer = FIRST_BUFFER;
sscProcessor->shadowBuffer = SECOND_BUFFER;
}
if (STATUS & AT91C_SSC_RXBUFF)
{
#ifdef SSC_ENABLE_IRQ_RESETS_SSC
__SSC_PeripheryInit();
// forcibly enable IRQ
AT91C_BASE_SSC->SSC_IER = AT91C_SSC_ENDRX | AT91C_SSC_RXBUFF;
#endif
// we've lost both buffers, need to reprogram all and to restart transfer
// restarting Xchange
// disable transmitter and PDC
#ifdef SSC_ENABLE_IRQ_RESETS_SSC
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXDIS | AT91C_SSC_TXDIS;
#endif
AT91C_BASE_SSC->SSC_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
//
unsigned short read = AT91C_BASE_SSC->SSC_RHR; // reading that shit for SSC clears itself
read = AT91C_BASE_SSC->SSC_RHR; // reading that shit !
read = AT91C_BASE_SSC->SSC_RHR; // reading that shit !
// current TX buffer
AT91C_BASE_SSC->SSC_TPR = (unsigned long)(sscProcessor->TXbuffers[ sscProcessor->mainBuffer ]);
AT91C_BASE_SSC->SSC_TCR = sscProcessor->buffersLength;
// current RX buffer
AT91C_BASE_SSC->SSC_RPR = (unsigned long)(sscProcessor->RXbuffers[ sscProcessor->mainBuffer ]);
AT91C_BASE_SSC->SSC_RCR = sscProcessor->buffersLength;
// starting RC/TM
AT91C_BASE_SSC->SSC_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
#ifdef SSC_ENABLE_IRQ_RESETS_SSC
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN;
#endif
// posting semaphore to signal codec 'bout buffers switched
OSSemPost( sscProcessor->buffersSwitchSemaphore );
}
/////////////////////////// /////////////////////////// ///////////////////////////
AT91C_BASE_AIC->AIC_IVR = 0;
AT91C_BASE_AIC->AIC_ICCR = (1 << AT91C_ID_SSC);
AT91C_BASE_AIC->AIC_EOICR = 0;
}
И код инициализации :
Код
void __SSC_PeripheryInit( void )
{
// SSC Control Register
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; /* (SSC) Software Reset */
// SSC Receive Clock Mode Register
AT91C_BASE_SSC->SSC_RCMR = ((0x2 << 0) & AT91C_SSC_CKS) | ((0x4 << 8) & AT91C_SSC_START);
// AT91C_BASE_SSC->SSC_RCMR = ((0x2 << 0) & AT91C_SSC_CKS) | AT91C_SSC_CKI | ((0x3 << 8) & AT91C_SSC_START);
// SSC Receive Frame Mode Register
AT91C_BASE_SSC->SSC_RFMR = ((15 << 0) & AT91C_SSC_DATLEN) | AT91C_SSC_MSBF;
// SSC Transmit Clock Mode Register
AT91C_BASE_SSC->SSC_TCMR = ((0x2 << 0) & AT91C_SSC_CKS) | AT91C_SSC_CKI | ((0x4 << 8) & AT91C_SSC_START);;
// SSC Transmit Frame Mode Register
AT91C_BASE_SSC->SSC_TFMR = ((15 << 0) & AT91C_SSC_DATLEN) | AT91C_SSC_MSBF;
}
{
// SSC Control Register
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; /* (SSC) Software Reset */
// SSC Receive Clock Mode Register
AT91C_BASE_SSC->SSC_RCMR = ((0x2 << 0) & AT91C_SSC_CKS) | ((0x4 << 8) & AT91C_SSC_START);
// AT91C_BASE_SSC->SSC_RCMR = ((0x2 << 0) & AT91C_SSC_CKS) | AT91C_SSC_CKI | ((0x3 << 8) & AT91C_SSC_START);
// SSC Receive Frame Mode Register
AT91C_BASE_SSC->SSC_RFMR = ((15 << 0) & AT91C_SSC_DATLEN) | AT91C_SSC_MSBF;
// SSC Transmit Clock Mode Register
AT91C_BASE_SSC->SSC_TCMR = ((0x2 << 0) & AT91C_SSC_CKS) | AT91C_SSC_CKI | ((0x4 << 8) & AT91C_SSC_START);;
// SSC Transmit Frame Mode Register
AT91C_BASE_SSC->SSC_TFMR = ((15 << 0) & AT91C_SSC_DATLEN) | AT91C_SSC_MSBF;
}